[{"data":1,"prerenderedAt":6226},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fadvanced\u002Fdownload-engine":713,"\u002Fdocs\u002Fadvanced\u002Fdownload-engine-surround":6221},[4,170,307,444,580],{"title":5,"path":6,"stem":7,"children":8,"page":32},"Docs","\u002Fdocs","1.docs",[9,33,74,95,134,154],{"title":10,"path":11,"stem":12,"children":13,"icon":32},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[14,17,22,27],{"title":15,"path":11,"stem":12,"icon":16},"Introduction","i-lucide-house",{"title":18,"path":19,"stem":20,"icon":21},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation","i-lucide-download",{"title":23,"path":24,"stem":25,"icon":26},"Usage Guide","\u002Fdocs\u002Fgetting-started\u002Fusage","1.docs\u002F1.getting-started\u002F3.usage","i-lucide-sliders",{"title":28,"path":29,"stem":30,"icon":31},"Configuration Reference","\u002Fdocs\u002Fgetting-started\u002Fconfiguration","1.docs\u002F1.getting-started\u002F4.configuration","i-lucide-settings",false,{"title":34,"icon":35,"path":36,"stem":37,"children":38,"page":32},"Features","i-lucide-star","\u002Fdocs\u002Ffeatures","1.docs\u002F2.features",[39,44,49,54,59,64,69],{"title":40,"path":41,"stem":42,"icon":43},"Video Sniffing","\u002Fdocs\u002Ffeatures\u002Fvideo-sniffing","1.docs\u002F2.features\u002F1.video-sniffing","i-lucide-video",{"title":45,"path":46,"stem":47,"icon":48},"Audio Capture","\u002Fdocs\u002Ffeatures\u002Faudio-capture","1.docs\u002F2.features\u002F2.audio-capture","i-lucide-music",{"title":50,"path":51,"stem":52,"icon":53},"Image Download","\u002Fdocs\u002Ffeatures\u002Fimage-download","1.docs\u002F2.features\u002F3.image-download","i-lucide-image",{"title":55,"path":56,"stem":57,"icon":58},"Privacy & Security","\u002Fdocs\u002Ffeatures\u002Fprivacy-security","1.docs\u002F2.features\u002F4.privacy-security","i-lucide-shield-check",{"title":60,"path":61,"stem":62,"icon":63},"Format Conversion","\u002Fdocs\u002Ffeatures\u002Fformat-conversion","1.docs\u002F2.features\u002F5.format-conversion","i-lucide-arrow-left-right",{"title":65,"path":66,"stem":67,"icon":68},"Batch Download","\u002Fdocs\u002Ffeatures\u002Fbatch-download","1.docs\u002F2.features\u002F6.batch-download","i-lucide-layers",{"title":70,"path":71,"stem":72,"icon":73},"Keyboard Shortcuts","\u002Fdocs\u002Ffeatures\u002Fkeyboard-shortcuts","1.docs\u002F2.features\u002F7.keyboard-shortcuts","i-lucide-keyboard",{"title":75,"icon":76,"path":77,"stem":78,"children":79,"page":32},"Advanced","i-lucide-book-open","\u002Fdocs\u002Fadvanced","1.docs\u002F3.advanced",[80,85,90],{"title":81,"path":82,"stem":83,"icon":84},"Online Tools","\u002Fdocs\u002Fadvanced\u002Fonline-tools","1.docs\u002F3.advanced\u002F1.online-tools","i-lucide-globe",{"title":86,"path":87,"stem":88,"icon":89},"Browser Compatibility","\u002Fdocs\u002Fadvanced\u002Fbrowser-compatibility","1.docs\u002F3.advanced\u002F2.browser-compatibility","i-lucide-monitor-check",{"title":91,"path":92,"stem":93,"icon":94},"Download Engine Architecture","\u002Fdocs\u002Fadvanced\u002Fdownload-engine","1.docs\u002F3.advanced\u002F3.download-engine","i-lucide-cpu",{"title":96,"icon":97,"path":98,"stem":99,"children":100,"page":32},"Use Cases","i-lucide-lightbulb","\u002Fdocs\u002Fusecases","1.docs\u002F4.usecases",[101,106,110,115,120,124,129],{"title":102,"path":103,"stem":104,"icon":105},"Online Courses & Educational Platforms","\u002Fdocs\u002Fusecases\u002Fonline-courses","1.docs\u002F4.usecases\u002F1.online-courses","i-lucide-graduation-cap",{"title":107,"path":108,"stem":109,"icon":43},"Video Platforms & UGC Content","\u002Fdocs\u002Fusecases\u002Fvideo-platforms","1.docs\u002F4.usecases\u002F2.video-platforms",{"title":111,"path":112,"stem":113,"icon":114},"Live Replays & Event Recordings","\u002Fdocs\u002Fusecases\u002Flive-replays","1.docs\u002F4.usecases\u002F3.live-replays","i-lucide-radio",{"title":116,"path":117,"stem":118,"icon":119},"Podcasts & Audio Content","\u002Fdocs\u002Fusecases\u002Fpodcasts-audio","1.docs\u002F4.usecases\u002F4.podcasts-audio","i-lucide-headphones",{"title":121,"path":122,"stem":123,"icon":53},"Image Galleries & Wallpaper Batch Download","\u002Fdocs\u002Fusecases\u002Fimage-galleries","1.docs\u002F4.usecases\u002F5.image-galleries",{"title":125,"path":126,"stem":127,"icon":128},"Corporate Training & Internal Videos","\u002Fdocs\u002Fusecases\u002Fcorporate-training","1.docs\u002F4.usecases\u002F6.corporate-training","i-lucide-building-2",{"title":130,"path":131,"stem":132,"icon":133},"Personal Media Archiving & Collection","\u002Fdocs\u002Fusecases\u002Fpersonal-archiving","1.docs\u002F4.usecases\u002F7.personal-archiving","i-lucide-archive",{"title":135,"icon":136,"path":137,"stem":138,"children":139,"page":32},"Troubleshooting","i-lucide-wrench","\u002Fdocs\u002Ftroubleshooting","1.docs\u002F5.troubleshooting",[140,144,149],{"title":141,"path":142,"stem":143,"icon":136},"Common Issues Troubleshooting","\u002Fdocs\u002Ftroubleshooting\u002Fcommon-issues","1.docs\u002F5.troubleshooting\u002F1.common-issues",{"title":145,"path":146,"stem":147,"icon":148},"Known Limitations & Caveats","\u002Fdocs\u002Ftroubleshooting\u002Fknown-issues","1.docs\u002F5.troubleshooting\u002F2.known-issues","i-lucide-alert-triangle",{"title":150,"path":151,"stem":152,"icon":153},"FAQ","\u002Fdocs\u002Ftroubleshooting\u002Ffaq","1.docs\u002F5.troubleshooting\u002F3.faq","i-lucide-message-circle-question",{"title":155,"icon":156,"path":157,"stem":158,"children":159,"page":32},"Developer Docs","i-lucide-code","\u002Fdocs\u002Fdeveloper","1.docs\u002F6.developer",[160,165],{"title":161,"path":162,"stem":163,"icon":164},"Contributing Guide","\u002Fdocs\u002Fdeveloper\u002Fcontributing","1.docs\u002F6.developer\u002F1.contributing","i-lucide-git-pull-request",{"title":166,"path":167,"stem":168,"icon":169},"Project Architecture","\u002Fdocs\u002Fdeveloper\u002Farchitecture","1.docs\u002F6.developer\u002F2.architecture","i-lucide-box",{"title":171,"path":172,"stem":173,"children":174,"page":32},"Ja","\u002Fja","ja",[175,194,227,244,277,294],{"title":176,"path":177,"stem":178,"children":179,"icon":32},"クイックスタート","\u002Fja\u002Fgetting-started","ja\u002F1.getting-started\u002F1.index",[180,182,186,190],{"title":181,"path":177,"stem":178,"icon":16},"概要",{"title":183,"path":184,"stem":185,"icon":21},"インストール","\u002Fja\u002Fgetting-started\u002Finstallation","ja\u002F1.getting-started\u002F2.installation",{"title":187,"path":188,"stem":189,"icon":26},"使用方法","\u002Fja\u002Fgetting-started\u002Fusage","ja\u002F1.getting-started\u002F3.usage",{"title":191,"path":192,"stem":193,"icon":31},"設定リファレンス","\u002Fja\u002Fgetting-started\u002Fconfiguration","ja\u002F1.getting-started\u002F4.configuration",{"title":195,"icon":35,"path":196,"stem":197,"children":198,"page":32},"機能","\u002Fja\u002Ffeatures","ja\u002F2.features",[199,203,207,211,215,219,223],{"title":200,"path":201,"stem":202,"icon":43},"動画検知","\u002Fja\u002Ffeatures\u002Fvideo-sniffing","ja\u002F2.features\u002F1.video-sniffing",{"title":204,"path":205,"stem":206,"icon":48},"音声キャプチャ","\u002Fja\u002Ffeatures\u002Faudio-capture","ja\u002F2.features\u002F2.audio-capture",{"title":208,"path":209,"stem":210,"icon":53},"画像ダウンロード","\u002Fja\u002Ffeatures\u002Fimage-download","ja\u002F2.features\u002F3.image-download",{"title":212,"path":213,"stem":214,"icon":58},"プライバシーとセキュリティ","\u002Fja\u002Ffeatures\u002Fprivacy-security","ja\u002F2.features\u002F4.privacy-security",{"title":216,"path":217,"stem":218,"icon":63},"フォーマット変換","\u002Fja\u002Ffeatures\u002Fformat-conversion","ja\u002F2.features\u002F5.format-conversion",{"title":220,"path":221,"stem":222,"icon":68},"一括ダウンロード","\u002Fja\u002Ffeatures\u002Fbatch-download","ja\u002F2.features\u002F6.batch-download",{"title":224,"path":225,"stem":226,"icon":73},"キーボードショートカット","\u002Fja\u002Ffeatures\u002Fkeyboard-shortcuts","ja\u002F2.features\u002F7.keyboard-shortcuts",{"title":228,"icon":76,"path":229,"stem":230,"children":231,"page":32},"詳細情報","\u002Fja\u002Fadvanced","ja\u002F3.advanced",[232,236,240],{"title":233,"path":234,"stem":235,"icon":84},"オンラインツール","\u002Fja\u002Fadvanced\u002Fonline-tools","ja\u002F3.advanced\u002F1.online-tools",{"title":237,"path":238,"stem":239,"icon":89},"ブラウザ互換性","\u002Fja\u002Fadvanced\u002Fbrowser-compatibility","ja\u002F3.advanced\u002F2.browser-compatibility",{"title":241,"path":242,"stem":243,"icon":94},"ダウンロードエンジンアーキテクチャ","\u002Fja\u002Fadvanced\u002Fdownload-engine","ja\u002F3.advanced\u002F3.download-engine",{"title":245,"icon":97,"path":246,"stem":247,"children":248,"page":32},"ユースケース","\u002Fja\u002Fusecases","ja\u002F4.usecases",[249,253,257,261,265,269,273],{"title":250,"path":251,"stem":252,"icon":105},"オンラインコースと教育プラットフォーム","\u002Fja\u002Fusecases\u002Fonline-courses","ja\u002F4.usecases\u002F1.online-courses",{"title":254,"path":255,"stem":256,"icon":43},"動画プラットフォームと UGC コンテンツ","\u002Fja\u002Fusecases\u002Fvideo-platforms","ja\u002F4.usecases\u002F2.video-platforms",{"title":258,"path":259,"stem":260,"icon":114},"ライブ配信アーカイブと競技録画","\u002Fja\u002Fusecases\u002Flive-replays","ja\u002F4.usecases\u002F3.live-replays",{"title":262,"path":263,"stem":264,"icon":119},"ポッドキャストとオーディオコンテンツ","\u002Fja\u002Fusecases\u002Fpodcasts-audio","ja\u002F4.usecases\u002F4.podcasts-audio",{"title":266,"path":267,"stem":268,"icon":53},"ギャラリーと壁紙の一括ダウンロード","\u002Fja\u002Fusecases\u002Fimage-galleries","ja\u002F4.usecases\u002F5.image-galleries",{"title":270,"path":271,"stem":272,"icon":128},"企業研修と内部動画","\u002Fja\u002Fusecases\u002Fcorporate-training","ja\u002F4.usecases\u002F6.corporate-training",{"title":274,"path":275,"stem":276,"icon":133},"個人メディアコレクションとアーカイブ","\u002Fja\u002Fusecases\u002Fpersonal-archiving","ja\u002F4.usecases\u002F7.personal-archiving",{"title":278,"icon":136,"path":279,"stem":280,"children":281,"page":32},"トラブルシューティング","\u002Fja\u002Ftroubleshooting","ja\u002F5.troubleshooting",[282,286,290],{"title":283,"path":284,"stem":285,"icon":136},"一般的な問題のトラブルシューティング","\u002Fja\u002Ftroubleshooting\u002Fcommon-issues","ja\u002F5.troubleshooting\u002F1.common-issues",{"title":287,"path":288,"stem":289,"icon":148},"既知の制限事項と注意点","\u002Fja\u002Ftroubleshooting\u002Fknown-issues","ja\u002F5.troubleshooting\u002F2.known-issues",{"title":291,"path":292,"stem":293,"icon":153},"よくある質問","\u002Fja\u002Ftroubleshooting\u002Ffaq","ja\u002F5.troubleshooting\u002F3.faq",{"title":295,"icon":156,"path":296,"stem":297,"children":298,"page":32},"開発者ガイド","\u002Fja\u002Fdeveloper","ja\u002F6.developer",[299,303],{"title":300,"path":301,"stem":302,"icon":164},"貢献ガイド","\u002Fja\u002Fdeveloper\u002Fcontributing","ja\u002F6.developer\u002F1.contributing",{"title":304,"path":305,"stem":306,"icon":169},"プロジェクトアーキテクチャ","\u002Fja\u002Fdeveloper\u002Farchitecture","ja\u002F6.developer\u002F2.architecture",{"title":308,"path":309,"stem":310,"children":311,"page":32},"Ko","\u002Fko","ko",[312,331,364,381,414,431],{"title":313,"path":314,"stem":315,"children":316,"icon":32},"빠른 시작","\u002Fko\u002Fgetting-started","ko\u002F1.getting-started\u002F1.index",[317,319,323,327],{"title":318,"path":314,"stem":315,"icon":16},"소개",{"title":320,"path":321,"stem":322,"icon":21},"설치","\u002Fko\u002Fgetting-started\u002Finstallation","ko\u002F1.getting-started\u002F2.installation",{"title":324,"path":325,"stem":326,"icon":26},"사용 방법","\u002Fko\u002Fgetting-started\u002Fusage","ko\u002F1.getting-started\u002F3.usage",{"title":328,"path":329,"stem":330,"icon":31},"설정 참조","\u002Fko\u002Fgetting-started\u002Fconfiguration","ko\u002F1.getting-started\u002F4.configuration",{"title":332,"icon":35,"path":333,"stem":334,"children":335,"page":32},"기능","\u002Fko\u002Ffeatures","ko\u002F2.features",[336,340,344,348,352,356,360],{"title":337,"path":338,"stem":339,"icon":43},"비디오 스니핑","\u002Fko\u002Ffeatures\u002Fvideo-sniffing","ko\u002F2.features\u002F1.video-sniffing",{"title":341,"path":342,"stem":343,"icon":48},"오디오 캡처","\u002Fko\u002Ffeatures\u002Faudio-capture","ko\u002F2.features\u002F2.audio-capture",{"title":345,"path":346,"stem":347,"icon":53},"이미지 다운로드","\u002Fko\u002Ffeatures\u002Fimage-download","ko\u002F2.features\u002F3.image-download",{"title":349,"path":350,"stem":351,"icon":58},"개인정보 보호와 보안","\u002Fko\u002Ffeatures\u002Fprivacy-security","ko\u002F2.features\u002F4.privacy-security",{"title":353,"path":354,"stem":355,"icon":63},"포맷 변환","\u002Fko\u002Ffeatures\u002Fformat-conversion","ko\u002F2.features\u002F5.format-conversion",{"title":357,"path":358,"stem":359,"icon":68},"일괄 다운로드","\u002Fko\u002Ffeatures\u002Fbatch-download","ko\u002F2.features\u002F6.batch-download",{"title":361,"path":362,"stem":363,"icon":73},"키보드 단축키","\u002Fko\u002Ffeatures\u002Fkeyboard-shortcuts","ko\u002F2.features\u002F7.keyboard-shortcuts",{"title":365,"icon":76,"path":366,"stem":367,"children":368,"page":32},"고급 가이드","\u002Fko\u002Fadvanced","ko\u002F3.advanced",[369,373,377],{"title":370,"path":371,"stem":372,"icon":84},"온라인 도구","\u002Fko\u002Fadvanced\u002Fonline-tools","ko\u002F3.advanced\u002F1.online-tools",{"title":374,"path":375,"stem":376,"icon":89},"브라우저 호환성","\u002Fko\u002Fadvanced\u002Fbrowser-compatibility","ko\u002F3.advanced\u002F2.browser-compatibility",{"title":378,"path":379,"stem":380,"icon":94},"다운로드 엔진 아키텍처","\u002Fko\u002Fadvanced\u002Fdownload-engine","ko\u002F3.advanced\u002F3.download-engine",{"title":382,"icon":97,"path":383,"stem":384,"children":385,"page":32},"사용 사례","\u002Fko\u002Fusecases","ko\u002F4.usecases",[386,390,394,398,402,406,410],{"title":387,"path":388,"stem":389,"icon":105},"온라인 강좌 및 교육 플랫폼","\u002Fko\u002Fusecases\u002Fonline-courses","ko\u002F4.usecases\u002F1.online-courses",{"title":391,"path":392,"stem":393,"icon":43},"비디오 플랫폼 및 UGC 콘텐츠","\u002Fko\u002Fusecases\u002Fvideo-platforms","ko\u002F4.usecases\u002F2.video-platforms",{"title":395,"path":396,"stem":397,"icon":114},"라이브 방송 재생 및 경기 녹화","\u002Fko\u002Fusecases\u002Flive-replays","ko\u002F4.usecases\u002F3.live-replays",{"title":399,"path":400,"stem":401,"icon":119},"팟캐스트 및 오디오 콘텐츠","\u002Fko\u002Fusecases\u002Fpodcasts-audio","ko\u002F4.usecases\u002F4.podcasts-audio",{"title":403,"path":404,"stem":405,"icon":53},"이미지 갤러리 및 배경화면 일괄 다운로드","\u002Fko\u002Fusecases\u002Fimage-galleries","ko\u002F4.usecases\u002F5.image-galleries",{"title":407,"path":408,"stem":409,"icon":128},"기업 교육 및 내부 비디오","\u002Fko\u002Fusecases\u002Fcorporate-training","ko\u002F4.usecases\u002F6.corporate-training",{"title":411,"path":412,"stem":413,"icon":133},"개인 미디어 수집 및 보관","\u002Fko\u002Fusecases\u002Fpersonal-archiving","ko\u002F4.usecases\u002F7.personal-archiving",{"title":415,"icon":136,"path":416,"stem":417,"children":418,"page":32},"문제 해결","\u002Fko\u002Ftroubleshooting","ko\u002F5.troubleshooting",[419,423,427],{"title":420,"path":421,"stem":422,"icon":136},"일반적인 문제 해결","\u002Fko\u002Ftroubleshooting\u002Fcommon-issues","ko\u002F5.troubleshooting\u002F1.common-issues",{"title":424,"path":425,"stem":426,"icon":148},"알려진 제한 사항 및 주의사항","\u002Fko\u002Ftroubleshooting\u002Fknown-issues","ko\u002F5.troubleshooting\u002F2.known-issues",{"title":428,"path":429,"stem":430,"icon":153},"자주 묻는 질문","\u002Fko\u002Ftroubleshooting\u002Ffaq","ko\u002F5.troubleshooting\u002F3.faq",{"title":432,"icon":156,"path":433,"stem":434,"children":435,"page":32},"개발자 문서","\u002Fko\u002Fdeveloper","ko\u002F6.developer",[436,440],{"title":437,"path":438,"stem":439,"icon":164},"기여 가이드라인","\u002Fko\u002Fdeveloper\u002Fcontributing","ko\u002F6.developer\u002F1.contributing",{"title":441,"path":442,"stem":443,"icon":169},"프로젝트 아키텍처","\u002Fko\u002Fdeveloper\u002Farchitecture","ko\u002F6.developer\u002F2.architecture",{"title":445,"path":446,"stem":447,"children":448,"page":32},"Zh Hans","\u002Fzh-hans","zh-Hans",[449,467,500,517,550,567],{"title":450,"path":451,"stem":452,"children":453,"icon":32},"快速开始","\u002Fzh-hans\u002Fgetting-started","zh-Hans\u002F1.getting-started\u002F1.index",[454,456,460,463],{"title":455,"path":451,"stem":452,"icon":16},"简介",{"title":457,"path":458,"stem":459,"icon":21},"安装","\u002Fzh-hans\u002Fgetting-started\u002Finstallation","zh-Hans\u002F1.getting-started\u002F2.installation",{"title":187,"path":461,"stem":462,"icon":26},"\u002Fzh-hans\u002Fgetting-started\u002Fusage","zh-Hans\u002F1.getting-started\u002F3.usage",{"title":464,"path":465,"stem":466,"icon":31},"配置参考","\u002Fzh-hans\u002Fgetting-started\u002Fconfiguration","zh-Hans\u002F1.getting-started\u002F4.configuration",{"title":468,"icon":35,"path":469,"stem":470,"children":471,"page":32},"功能特性","\u002Fzh-hans\u002Ffeatures","zh-Hans\u002F2.features",[472,476,480,484,488,492,496],{"title":473,"path":474,"stem":475,"icon":43},"视频嗅探","\u002Fzh-hans\u002Ffeatures\u002Fvideo-sniffing","zh-Hans\u002F2.features\u002F1.video-sniffing",{"title":477,"path":478,"stem":479,"icon":48},"音频捕获","\u002Fzh-hans\u002Ffeatures\u002Faudio-capture","zh-Hans\u002F2.features\u002F2.audio-capture",{"title":481,"path":482,"stem":483,"icon":53},"图片下载","\u002Fzh-hans\u002Ffeatures\u002Fimage-download","zh-Hans\u002F2.features\u002F3.image-download",{"title":485,"path":486,"stem":487,"icon":58},"隐私与安全","\u002Fzh-hans\u002Ffeatures\u002Fprivacy-security","zh-Hans\u002F2.features\u002F4.privacy-security",{"title":489,"path":490,"stem":491,"icon":63},"格式转换","\u002Fzh-hans\u002Ffeatures\u002Fformat-conversion","zh-Hans\u002F2.features\u002F5.format-conversion",{"title":493,"path":494,"stem":495,"icon":68},"批量下载","\u002Fzh-hans\u002Ffeatures\u002Fbatch-download","zh-Hans\u002F2.features\u002F6.batch-download",{"title":497,"path":498,"stem":499,"icon":73},"键盘快捷键","\u002Fzh-hans\u002Ffeatures\u002Fkeyboard-shortcuts","zh-Hans\u002F2.features\u002F7.keyboard-shortcuts",{"title":501,"icon":76,"path":502,"stem":503,"children":504,"page":32},"高级指南","\u002Fzh-hans\u002Fadvanced","zh-Hans\u002F3.advanced",[505,509,513],{"title":506,"path":507,"stem":508,"icon":84},"在线工具","\u002Fzh-hans\u002Fadvanced\u002Fonline-tools","zh-Hans\u002F3.advanced\u002F1.online-tools",{"title":510,"path":511,"stem":512,"icon":89},"浏览器兼容性","\u002Fzh-hans\u002Fadvanced\u002Fbrowser-compatibility","zh-Hans\u002F3.advanced\u002F2.browser-compatibility",{"title":514,"path":515,"stem":516,"icon":94},"下载引擎架构","\u002Fzh-hans\u002Fadvanced\u002Fdownload-engine","zh-Hans\u002F3.advanced\u002F3.download-engine",{"title":518,"icon":97,"path":519,"stem":520,"children":521,"page":32},"使用场景","\u002Fzh-hans\u002Fusecases","zh-Hans\u002F4.usecases",[522,526,530,534,538,542,546],{"title":523,"path":524,"stem":525,"icon":105},"在线课程与教育平台","\u002Fzh-hans\u002Fusecases\u002Fonline-courses","zh-Hans\u002F4.usecases\u002F1.online-courses",{"title":527,"path":528,"stem":529,"icon":43},"视频平台与 UGC 内容","\u002Fzh-hans\u002Fusecases\u002Fvideo-platforms","zh-Hans\u002F4.usecases\u002F2.video-platforms",{"title":531,"path":532,"stem":533,"icon":114},"直播回放与赛事录像","\u002Fzh-hans\u002Fusecases\u002Flive-replays","zh-Hans\u002F4.usecases\u002F3.live-replays",{"title":535,"path":536,"stem":537,"icon":119},"播客与音频内容","\u002Fzh-hans\u002Fusecases\u002Fpodcasts-audio","zh-Hans\u002F4.usecases\u002F4.podcasts-audio",{"title":539,"path":540,"stem":541,"icon":53},"图库与壁纸批量下载","\u002Fzh-hans\u002Fusecases\u002Fimage-galleries","zh-Hans\u002F4.usecases\u002F5.image-galleries",{"title":543,"path":544,"stem":545,"icon":128},"企业培训与内部视频","\u002Fzh-hans\u002Fusecases\u002Fcorporate-training","zh-Hans\u002F4.usecases\u002F6.corporate-training",{"title":547,"path":548,"stem":549,"icon":133},"个人媒体收藏与归档","\u002Fzh-hans\u002Fusecases\u002Fpersonal-archiving","zh-Hans\u002F4.usecases\u002F7.personal-archiving",{"title":551,"icon":136,"path":552,"stem":553,"children":554,"page":32},"故障排除","\u002Fzh-hans\u002Ftroubleshooting","zh-Hans\u002F5.troubleshooting",[555,559,563],{"title":556,"path":557,"stem":558,"icon":136},"常见问题排查","\u002Fzh-hans\u002Ftroubleshooting\u002Fcommon-issues","zh-Hans\u002F5.troubleshooting\u002F1.common-issues",{"title":560,"path":561,"stem":562,"icon":148},"已知限制与注意事项","\u002Fzh-hans\u002Ftroubleshooting\u002Fknown-issues","zh-Hans\u002F5.troubleshooting\u002F2.known-issues",{"title":564,"path":565,"stem":566,"icon":153},"常见问题解答","\u002Fzh-hans\u002Ftroubleshooting\u002Ffaq","zh-Hans\u002F5.troubleshooting\u002F3.faq",{"title":568,"icon":156,"path":569,"stem":570,"children":571,"page":32},"开发者文档","\u002Fzh-hans\u002Fdeveloper","zh-Hans\u002F6.developer",[572,576],{"title":573,"path":574,"stem":575,"icon":164},"贡献指南","\u002Fzh-hans\u002Fdeveloper\u002Fcontributing","zh-Hans\u002F6.developer\u002F1.contributing",{"title":577,"path":578,"stem":579,"icon":169},"项目架构","\u002Fzh-hans\u002Fdeveloper\u002Farchitecture","zh-Hans\u002F6.developer\u002F2.architecture",{"title":581,"path":582,"stem":583,"children":584,"page":32},"Zh Hant","\u002Fzh-hant","zh-Hant",[585,603,636,652,684,701],{"title":586,"path":587,"stem":588,"children":589,"icon":32},"快速入門","\u002Fzh-hant\u002Fgetting-started","zh-Hant\u002F1.getting-started\u002F1.index",[590,592,596,599],{"title":591,"path":587,"stem":588,"icon":16},"簡介",{"title":593,"path":594,"stem":595,"icon":21},"安裝","\u002Fzh-hant\u002Fgetting-started\u002Finstallation","zh-Hant\u002F1.getting-started\u002F2.installation",{"title":187,"path":597,"stem":598,"icon":26},"\u002Fzh-hant\u002Fgetting-started\u002Fusage","zh-Hant\u002F1.getting-started\u002F3.usage",{"title":600,"path":601,"stem":602,"icon":31},"配置參考","\u002Fzh-hant\u002Fgetting-started\u002Fconfiguration","zh-Hant\u002F1.getting-started\u002F4.configuration",{"title":604,"icon":35,"path":605,"stem":606,"children":607,"page":32},"功能特色","\u002Fzh-hant\u002Ffeatures","zh-Hant\u002F2.features",[608,612,616,620,624,628,632],{"title":609,"path":610,"stem":611,"icon":43},"影片嗅探","\u002Fzh-hant\u002Ffeatures\u002Fvideo-sniffing","zh-Hant\u002F2.features\u002F1.video-sniffing",{"title":613,"path":614,"stem":615,"icon":48},"音訊擷取","\u002Fzh-hant\u002Ffeatures\u002Faudio-capture","zh-Hant\u002F2.features\u002F2.audio-capture",{"title":617,"path":618,"stem":619,"icon":53},"圖片下載","\u002Fzh-hant\u002Ffeatures\u002Fimage-download","zh-Hant\u002F2.features\u002F3.image-download",{"title":621,"path":622,"stem":623,"icon":58},"隱私與安全","\u002Fzh-hant\u002Ffeatures\u002Fprivacy-security","zh-Hant\u002F2.features\u002F4.privacy-security",{"title":625,"path":626,"stem":627,"icon":63},"格式轉換","\u002Fzh-hant\u002Ffeatures\u002Fformat-conversion","zh-Hant\u002F2.features\u002F5.format-conversion",{"title":629,"path":630,"stem":631,"icon":68},"批次下載","\u002Fzh-hant\u002Ffeatures\u002Fbatch-download","zh-Hant\u002F2.features\u002F6.batch-download",{"title":633,"path":634,"stem":635,"icon":73},"鍵盤快速鍵","\u002Fzh-hant\u002Ffeatures\u002Fkeyboard-shortcuts","zh-Hant\u002F2.features\u002F7.keyboard-shortcuts",{"title":501,"icon":76,"path":637,"stem":638,"children":639,"page":32},"\u002Fzh-hant\u002Fadvanced","zh-Hant\u002F3.advanced",[640,644,648],{"title":641,"path":642,"stem":643,"icon":84},"線上工具","\u002Fzh-hant\u002Fadvanced\u002Fonline-tools","zh-Hant\u002F3.advanced\u002F1.online-tools",{"title":645,"path":646,"stem":647,"icon":89},"瀏覽器相容性","\u002Fzh-hant\u002Fadvanced\u002Fbrowser-compatibility","zh-Hant\u002F3.advanced\u002F2.browser-compatibility",{"title":649,"path":650,"stem":651,"icon":94},"下載引擎架構","\u002Fzh-hant\u002Fadvanced\u002Fdownload-engine","zh-Hant\u002F3.advanced\u002F3.download-engine",{"title":518,"icon":97,"path":653,"stem":654,"children":655,"page":32},"\u002Fzh-hant\u002Fusecases","zh-Hant\u002F4.usecases",[656,660,664,668,672,676,680],{"title":657,"path":658,"stem":659,"icon":105},"線上課程與教育平台","\u002Fzh-hant\u002Fusecases\u002Fonline-courses","zh-Hant\u002F4.usecases\u002F1.online-courses",{"title":661,"path":662,"stem":663,"icon":43},"影片平台與 UGC 內容","\u002Fzh-hant\u002Fusecases\u002Fvideo-platforms","zh-Hant\u002F4.usecases\u002F2.video-platforms",{"title":665,"path":666,"stem":667,"icon":114},"直播回放與賽事錄影","\u002Fzh-hant\u002Fusecases\u002Flive-replays","zh-Hant\u002F4.usecases\u002F3.live-replays",{"title":669,"path":670,"stem":671,"icon":119},"播客與音訊內容","\u002Fzh-hant\u002Fusecases\u002Fpodcasts-audio","zh-Hant\u002F4.usecases\u002F4.podcasts-audio",{"title":673,"path":674,"stem":675,"icon":53},"圖庫與桌布批次下載","\u002Fzh-hant\u002Fusecases\u002Fimage-galleries","zh-Hant\u002F4.usecases\u002F5.image-galleries",{"title":677,"path":678,"stem":679,"icon":128},"企業培訓與內部影片","\u002Fzh-hant\u002Fusecases\u002Fcorporate-training","zh-Hant\u002F4.usecases\u002F6.corporate-training",{"title":681,"path":682,"stem":683,"icon":133},"個人媒體收藏與歸檔","\u002Fzh-hant\u002Fusecases\u002Fpersonal-archiving","zh-Hant\u002F4.usecases\u002F7.personal-archiving",{"title":685,"icon":136,"path":686,"stem":687,"children":688,"page":32},"疑難排解","\u002Fzh-hant\u002Ftroubleshooting","zh-Hant\u002F5.troubleshooting",[689,693,697],{"title":690,"path":691,"stem":692,"icon":136},"常見問題排查","\u002Fzh-hant\u002Ftroubleshooting\u002Fcommon-issues","zh-Hant\u002F5.troubleshooting\u002F1.common-issues",{"title":694,"path":695,"stem":696,"icon":148},"已知限制與注意事項","\u002Fzh-hant\u002Ftroubleshooting\u002Fknown-issues","zh-Hant\u002F5.troubleshooting\u002F2.known-issues",{"title":698,"path":699,"stem":700,"icon":153},"常見問題解答","\u002Fzh-hant\u002Ftroubleshooting\u002Ffaq","zh-Hant\u002F5.troubleshooting\u002F3.faq",{"title":568,"icon":156,"path":702,"stem":703,"children":704,"page":32},"\u002Fzh-hant\u002Fdeveloper","zh-Hant\u002F6.developer",[705,709],{"title":706,"path":707,"stem":708,"icon":164},"貢獻指南","\u002Fzh-hant\u002Fdeveloper\u002Fcontributing","zh-Hant\u002F6.developer\u002F1.contributing",{"title":710,"path":711,"stem":712,"icon":169},"專案架構","\u002Fzh-hant\u002Fdeveloper\u002Farchitecture","zh-Hant\u002F6.developer\u002F2.architecture",{"id":714,"title":91,"body":715,"description":6215,"extension":6216,"meta":6217,"navigation":6218,"path":92,"seo":6219,"stem":93,"__hash__":6220},"docs\u002F1.docs\u002F3.advanced\u002F3.download-engine.md",{"type":716,"value":717,"toc":6171},"minimark",[718,722,729,732,737,740,751,756,759,765,783,787,790,796,803,805,809,813,816,1211,1217,1233,1238,1245,1251,1254,1271,1275,1278,1419,1424,1490,1496,1500,1503,1767,1772,1821,1826,1837,1851,1855,1968,1971,2043,2063,2067,2071,2074,2360,2365,2384,2389,2400,2417,2421,2424,2530,2533,2537,2543,2552,2556,2559,2565,2568,2598,2616,2620,2623,2629,2633,3086,3091,3102,3107,3119,3123,3240,3244,3252,3256,3275,3279,3423,3427,3444,3448,3535,3554,3558,3564,3568,3571,3855,3860,3883,3887,3893,3897,3963,3967,3970,4146,4152,4163,4175,4179,4183,4186,4601,4606,4626,4631,4681,4685,4688,5021,5026,5041,5045,5048,5289,5294,5297,5435,5437,5441,5445,5452,5610,5615,5621,5625,5631,5637,5644,5656,5660,5663,5800,5805,5875,5879,5885,5894,5898,5901,5907,5912,6070,6084,6088,6167],[719,720,721],"p",{},"FlowPick's download engine is the core of the entire system, responsible for downloading streaming segments, decrypting, merging them, and writing to disk. This document is for developers and advanced users who want to deeply understand the internal mechanisms.",[719,723,724],{},[725,726],"img",{"alt":727,"src":728},"Download Engine Architecture Overview","\u002Fscreenshots\u002Fdownload-engine-architecture.png",[730,731],"hr",{},[733,734,736],"h2",{"id":735},"architecture-overview","Architecture Overview",[719,738,739],{},"Download engine consists of three core modules, with data flowing through each module in pipeline fashion:",[741,742,747],"pre",{"className":743,"code":745,"language":746},[744],"language-text","┌─────────────────────────────────────────────────┐\n│                   Download Engine                 │\n│                                                  │\n│  ┌──────────┐  ┌──────────┐  ┌───────────────┐  │\n│  │ Segment   │→│ Segment   │→│ File Writing    │  │\n│  │ Download  │  │ Process  │  │ Module          │  │\n│  │ Module    │  │ Module   │  │                 │  │\n│  │          │  │          │  │                 │  │\n│  │ · Concur- │  │ · Decrypt│  │ · FSA Streaming│  │\n│  │   rency  │  │ · Concat │  │ · StreamSaver   │  │\n│  │ · Retry  │  │ · Remux  │  │ · Blob Fallback │  │\n│  └──────────┘  └──────────┘  └───────────────┘  │\n│                                                  │\n│  ┌─────────────────────────────────────────────┐ │\n│  │           Memory Safety Manager              │ │\n│  │  · Size Estimation · Threshold Check        │ │\n│  │  · Strategy Selection                       │ │\n│  └─────────────────────────────────────────────┘ │\n└─────────────────────────────────────────────────┘\n","text",[748,749,745],"code",{"__ignoreMap":750},"",[752,753,755],"h3",{"id":754},"full-data-flow","Full Data Flow",[719,757,758],{},"Complete chain from user clicking download to file written to disk:",[741,760,763],{"className":761,"code":762,"language":746},[744],"User clicks download\n    │\n    ▼\n┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│ 1. Manifest   │ ──→ │ 2. Segment    │ ──→ │ 3. Segment    │\n│    Parsing    │     │    Download   │     │    Processing │\n│              │     │               │     │               │\n│ · Download   │     │ · Worker Pool │     │ · AES Decrypt │\n│   M3U8       │     │ · Concurrency │     │ · TS Concat   │\n│ · Parse seg- │     │ · Exponential │     │ · FFmpeg Remux│\n│   ment list  │     │   backoff     │     │ · A\u002FV Merge   │\n│ · Extract    │     │ · Progress    │     │               │\n│   key        │     │   reporting   │     │               │\n│ · Estimate   │     │               │     │               │\n│   size       │     │               │     │               │\n└──────────────┘     └──────────────┘     └──────┬───────┘\n                                                  │\n                                                  ▼\n┌──────────────┐     ┌──────────────┐     ┌──────────────┐\n│ 6. Completion │ ←── │ 5. Cleanup   │ ←── │ 4. File Write │\n│ Notification │     │ & Recycling   │     │               │\n│              │     │               │     │               │\n│ · Desktop    │     │ · Release     │     │ · FSA Stream  │\n│   notifi-    │     │   memory      │     │ · StreamSaver │\n│   cation    │     │ · Clean temp  │     │ · Blob Fall-  │\n│ · Copy path  │     │   files       │     │   back        │\n│ · Queue adv- │     │ · Reset state │     │               │\n│   ance       │     │               │     │               │\n└──────────────┘     └──────────────┘     └──────────────┘\n",[748,764,762],{"__ignoreMap":750},[766,767,768],"note",{},[719,769,770,771,776,777,779,780,782],{},"For specific implementation of manifest parsing phase (Master Playlist vs Media Playlist, encryption detection), see ",[772,773,775],"a",{"href":774},"\u002Fdocs\u002Ffeatures\u002Fvideo-sniffing#hlsm3u8-streams","Video Sniffing — HLS Streams",". For FFmpeg remuxing details in segment processing, see ",[772,778,60],{"href":61},". For engine's position in overall system, see ",[772,781,166],{"href":167},".",[752,784,786],{"id":785},"engine-lifecycle","Engine Lifecycle",[719,788,789],{},"A complete run of download engine goes through following state transitions:",[741,791,794],{"className":792,"code":793,"language":746},[744],"  [Idle]\n    │ User triggers download\n    ▼\n  [Initializing] ─── Load WASM, check API availability, select write strategy\n    │\n    ▼\n  [Manifest Parsing] ── Download and parse M3U8\u002FMPD, extract segment list and keys\n    │\n    ▼\n  [Segment Download] ── Worker Pool concurrent download, real-time progress reporting\n    │\n    ▼\n  [Segment Processing] ── Decrypt → Concat\u002FRemux → Write to disk\n    │\n    ├── Success → [Cleanup] → [Complete] → [Idle]\n    │\n    ├── Cancel → [Cleanup] → [Idle]\n    │\n    └── Failure → [Cleanup] → [Error] → [Idle]\n",[748,795,793],{"__ignoreMap":750},[719,797,798,799,782],{},"Each state transition triggers corresponding lifecycle hooks; UI layer updates interface state by listening to these hooks. For UI-engine interaction details, see ",[772,800,802],{"href":801},"\u002Fdocs\u002Fdeveloper\u002Farchitecture#data-flow","Project Architecture — Data Flow",[730,804],{},[733,806,808],{"id":807},"segment-download-module","Segment Download Module",[752,810,812],{"id":811},"concurrent-downloader","Concurrent Downloader",[719,814,815],{},"Segment download uses Worker Pool pattern to implement concurrency control:",[741,817,821],{"className":818,"code":819,"language":820,"meta":750,"style":750},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const downloadSegmentsConcurrently = async (\n  segments: SegmentInfo[],\n  onSegmentDownloaded: (buffer: ArrayBuffer, index: number) => void\n) => {\n  const concurrency = Math.min(config.concurrency, 8)\n  let nextIndex = 0\n\n  const worker = async () => {\n    while (nextIndex \u003C segments.length) {\n      const index = nextIndex++\n      const buffer = await downloadWithRetry(segments[index]!)\n      onSegmentDownloaded(buffer, index)\n    }\n  }\n\n  const workers = Array.from(\n    { length: Math.min(concurrency, segments.length) },\n    () => worker()\n  )\n  await Promise.all(workers)\n}\n","typescript",[748,822,823,846,866,906,918,959,973,980,999,1027,1042,1077,1093,1099,1105,1110,1131,1165,1178,1184,1205],{"__ignoreMap":750},[824,825,828,832,836,840,843],"span",{"class":826,"line":827},"line",1,[824,829,831],{"class":830},"spNyl","const",[824,833,835],{"class":834},"sTEyZ"," downloadSegmentsConcurrently ",[824,837,839],{"class":838},"sMK4o","=",[824,841,842],{"class":830}," async",[824,844,845],{"class":834}," (\n",[824,847,849,853,856,860,863],{"class":826,"line":848},2,[824,850,852],{"class":851},"sHdIc","  segments",[824,854,855],{"class":838},":",[824,857,859],{"class":858},"sBMFI"," SegmentInfo",[824,861,862],{"class":834},"[]",[824,864,865],{"class":838},",\n",[824,867,869,873,875,878,881,883,886,889,892,894,897,900,903],{"class":826,"line":868},3,[824,870,872],{"class":871},"s2Zo4","  onSegmentDownloaded",[824,874,855],{"class":838},[824,876,877],{"class":838}," (",[824,879,880],{"class":851},"buffer",[824,882,855],{"class":838},[824,884,885],{"class":858}," ArrayBuffer",[824,887,888],{"class":838},",",[824,890,891],{"class":851}," index",[824,893,855],{"class":838},[824,895,896],{"class":858}," number",[824,898,899],{"class":838},")",[824,901,902],{"class":830}," =>",[824,904,905],{"class":858}," void\n",[824,907,909,912,915],{"class":826,"line":908},4,[824,910,911],{"class":834},") ",[824,913,914],{"class":830},"=>",[824,916,917],{"class":838}," {\n",[824,919,921,924,927,930,933,935,938,942,945,947,950,952,956],{"class":826,"line":920},5,[824,922,923],{"class":830},"  const",[824,925,926],{"class":834}," concurrency",[824,928,929],{"class":838}," =",[824,931,932],{"class":834}," Math",[824,934,782],{"class":838},[824,936,937],{"class":871},"min",[824,939,941],{"class":940},"swJcz","(",[824,943,944],{"class":834},"config",[824,946,782],{"class":838},[824,948,949],{"class":834},"concurrency",[824,951,888],{"class":838},[824,953,955],{"class":954},"sbssI"," 8",[824,957,958],{"class":940},")\n",[824,960,962,965,968,970],{"class":826,"line":961},6,[824,963,964],{"class":830},"  let",[824,966,967],{"class":834}," nextIndex",[824,969,929],{"class":838},[824,971,972],{"class":954}," 0\n",[824,974,976],{"class":826,"line":975},7,[824,977,979],{"emptyLinePlaceholder":978},true,"\n",[824,981,983,985,988,990,992,995,997],{"class":826,"line":982},8,[824,984,923],{"class":830},[824,986,987],{"class":834}," worker",[824,989,929],{"class":838},[824,991,842],{"class":830},[824,993,994],{"class":838}," ()",[824,996,902],{"class":830},[824,998,917],{"class":838},[824,1000,1002,1006,1008,1011,1014,1017,1019,1022,1024],{"class":826,"line":1001},9,[824,1003,1005],{"class":1004},"s7zQu","    while",[824,1007,877],{"class":940},[824,1009,1010],{"class":834},"nextIndex",[824,1012,1013],{"class":838}," \u003C",[824,1015,1016],{"class":834}," segments",[824,1018,782],{"class":838},[824,1020,1021],{"class":834},"length",[824,1023,911],{"class":940},[824,1025,1026],{"class":838},"{\n",[824,1028,1030,1033,1035,1037,1039],{"class":826,"line":1029},10,[824,1031,1032],{"class":830},"      const",[824,1034,891],{"class":834},[824,1036,929],{"class":838},[824,1038,967],{"class":834},[824,1040,1041],{"class":838},"++\n",[824,1043,1045,1047,1050,1052,1055,1058,1060,1063,1066,1069,1072,1075],{"class":826,"line":1044},11,[824,1046,1032],{"class":830},[824,1048,1049],{"class":834}," buffer",[824,1051,929],{"class":838},[824,1053,1054],{"class":1004}," await",[824,1056,1057],{"class":871}," downloadWithRetry",[824,1059,941],{"class":940},[824,1061,1062],{"class":834},"segments",[824,1064,1065],{"class":940},"[",[824,1067,1068],{"class":834},"index",[824,1070,1071],{"class":940},"]",[824,1073,1074],{"class":838},"!",[824,1076,958],{"class":940},[824,1078,1080,1083,1085,1087,1089,1091],{"class":826,"line":1079},12,[824,1081,1082],{"class":871},"      onSegmentDownloaded",[824,1084,941],{"class":940},[824,1086,880],{"class":834},[824,1088,888],{"class":838},[824,1090,891],{"class":834},[824,1092,958],{"class":940},[824,1094,1096],{"class":826,"line":1095},13,[824,1097,1098],{"class":838},"    }\n",[824,1100,1102],{"class":826,"line":1101},14,[824,1103,1104],{"class":838},"  }\n",[824,1106,1108],{"class":826,"line":1107},15,[824,1109,979],{"emptyLinePlaceholder":978},[824,1111,1113,1115,1118,1120,1123,1125,1128],{"class":826,"line":1112},16,[824,1114,923],{"class":830},[824,1116,1117],{"class":834}," workers",[824,1119,929],{"class":838},[824,1121,1122],{"class":834}," Array",[824,1124,782],{"class":838},[824,1126,1127],{"class":871},"from",[824,1129,1130],{"class":940},"(\n",[824,1132,1134,1137,1140,1142,1144,1146,1148,1150,1152,1154,1156,1158,1160,1162],{"class":826,"line":1133},17,[824,1135,1136],{"class":838},"    {",[824,1138,1139],{"class":940}," length",[824,1141,855],{"class":838},[824,1143,932],{"class":834},[824,1145,782],{"class":838},[824,1147,937],{"class":871},[824,1149,941],{"class":940},[824,1151,949],{"class":834},[824,1153,888],{"class":838},[824,1155,1016],{"class":834},[824,1157,782],{"class":838},[824,1159,1021],{"class":834},[824,1161,911],{"class":940},[824,1163,1164],{"class":838},"},\n",[824,1166,1168,1171,1173,1175],{"class":826,"line":1167},18,[824,1169,1170],{"class":838},"    ()",[824,1172,902],{"class":830},[824,1174,987],{"class":871},[824,1176,1177],{"class":940},"()\n",[824,1179,1181],{"class":826,"line":1180},19,[824,1182,1183],{"class":940},"  )\n",[824,1185,1187,1190,1193,1195,1198,1200,1203],{"class":826,"line":1186},20,[824,1188,1189],{"class":1004},"  await",[824,1191,1192],{"class":858}," Promise",[824,1194,782],{"class":838},[824,1196,1197],{"class":871},"all",[824,1199,941],{"class":940},[824,1201,1202],{"class":834},"workers",[824,1204,958],{"class":940},[824,1206,1208],{"class":826,"line":1207},21,[824,1209,1210],{"class":838},"}\n",[719,1212,1213,855],{},[1214,1215,1216],"strong",{},"Design Points",[1218,1219,1220,1227,1230],"ul",{},[1221,1222,1223,1224,1226],"li",{},"Use shared ",[748,1225,1010],{}," counter for task assignment, avoiding load imbalance from pre-splitting segments",[1221,1228,1229],{},"Worker count doesn't exceed total segment count, avoiding idle workers",[1221,1231,1232],{},"Each worker runs independently; single segment failure doesn't affect other workers",[1234,1235,1237],"h4",{"id":1236},"worker-pool-deep-dive","Worker Pool Deep Dive",[719,1239,1240,1241,1244],{},"Core advantage of Worker Pool pattern is ",[1214,1242,1243],{},"dynamic load balancing",". Unlike pre-splitting segment array into N equal parts, shared counter ensures:",[741,1246,1249],{"className":1247,"code":1248,"language":746},[744],"Pre-splitting (Not recommended):\nWorker 1: [Segment 0-49]   ← If these segments are larger, Worker 1 becomes bottleneck\nWorker 2: [Segment 50-99]  ← May finish early, then wait idle\n\nShared Counter (FlowPick's approach):\nWorker 1: Segment 0 → Segment 3 → Segment 5 → ...\nWorker 2: Segment 1 → Segment 4 → Segment 7 → ...\nWorker 3: Segment 2 → Segment 6 → Segment 8 → ...\n",[748,1250,1248],{"__ignoreMap":750},[719,1252,1253],{},"Each worker immediately grabs next unassigned segment after completing current one, until all segments processed. This pattern naturally adapts to scenarios with uneven segment sizes (e.g., HLS streams' first\u002Flast segments usually smaller, middle segments larger).",[1255,1256,1257],"tip",{},[719,1258,1259,1260,1263,1264,1266,1267,782],{},"Concurrency controlled by ",[748,1261,1262],{},"config.concurrency",", capped at 8. Users can adjust default value in ",[772,1265,28],{"href":29}," or modify in real-time on download interface. For queue scheduling in batch download scenarios, see ",[772,1268,1270],{"href":1269},"\u002Fdocs\u002Ffeatures\u002Fbatch-download#concurrency-selection-guide","Batch Download — Concurrency Selection Guide",[752,1272,1274],{"id":1273},"async-generator-pattern","Async Generator Pattern",[719,1276,1277],{},"For very large files (segment count > 500), engine uses AsyncGenerator pattern to avoid loading all segment data into memory at once:",[741,1279,1281],{"className":818,"code":1280,"language":820,"meta":750,"style":750},"async function* segmentGenerator(\n  segments: SegmentInfo[],\n  signal?: AbortSignal\n): AsyncGenerator\u003CArrayBuffer> {\n  for (const segment of segments) {\n    if (signal?.aborted) break\n    const buffer = await downloadWithRetry(segment)\n    yield buffer\n  }\n}\n",[748,1282,1283,1299,1311,1322,1341,1362,1383,1403,1411,1415],{"__ignoreMap":750},[824,1284,1285,1288,1291,1294,1297],{"class":826,"line":827},[824,1286,1287],{"class":830},"async",[824,1289,1290],{"class":830}," function",[824,1292,1293],{"class":838},"*",[824,1295,1296],{"class":871}," segmentGenerator",[824,1298,1130],{"class":838},[824,1300,1301,1303,1305,1307,1309],{"class":826,"line":848},[824,1302,852],{"class":851},[824,1304,855],{"class":838},[824,1306,859],{"class":858},[824,1308,862],{"class":834},[824,1310,865],{"class":838},[824,1312,1313,1316,1319],{"class":826,"line":868},[824,1314,1315],{"class":851},"  signal",[824,1317,1318],{"class":838},"?:",[824,1320,1321],{"class":858}," AbortSignal\n",[824,1323,1324,1327,1330,1333,1336,1339],{"class":826,"line":908},[824,1325,1326],{"class":838},"):",[824,1328,1329],{"class":858}," AsyncGenerator",[824,1331,1332],{"class":838},"\u003C",[824,1334,1335],{"class":858},"ArrayBuffer",[824,1337,1338],{"class":838},">",[824,1340,917],{"class":838},[824,1342,1343,1346,1348,1350,1353,1356,1358,1360],{"class":826,"line":920},[824,1344,1345],{"class":1004},"  for",[824,1347,877],{"class":940},[824,1349,831],{"class":830},[824,1351,1352],{"class":834}," segment",[824,1354,1355],{"class":838}," of",[824,1357,1016],{"class":834},[824,1359,911],{"class":940},[824,1361,1026],{"class":838},[824,1363,1364,1367,1369,1372,1375,1378,1380],{"class":826,"line":961},[824,1365,1366],{"class":1004},"    if",[824,1368,877],{"class":940},[824,1370,1371],{"class":834},"signal",[824,1373,1374],{"class":838},"?.",[824,1376,1377],{"class":834},"aborted",[824,1379,911],{"class":940},[824,1381,1382],{"class":1004},"break\n",[824,1384,1385,1388,1390,1392,1394,1396,1398,1401],{"class":826,"line":975},[824,1386,1387],{"class":830},"    const",[824,1389,1049],{"class":834},[824,1391,929],{"class":838},[824,1393,1054],{"class":1004},[824,1395,1057],{"class":871},[824,1397,941],{"class":940},[824,1399,1400],{"class":834},"segment",[824,1402,958],{"class":940},[824,1404,1405,1408],{"class":826,"line":982},[824,1406,1407],{"class":1004},"    yield",[824,1409,1410],{"class":834}," buffer\n",[824,1412,1413],{"class":826,"line":1001},[824,1414,1104],{"class":838},[824,1416,1417],{"class":826,"line":1029},[824,1418,1210],{"class":838},[719,1420,1421,855],{},[1214,1422,1423],{},"Difference from Array Pattern",[1425,1426,1427,1443],"table",{},[1428,1429,1430],"thead",{},[1431,1432,1433,1437,1440],"tr",{},[1434,1435,1436],"th",{},"Dimension",[1434,1438,1439],{},"Array Pattern",[1434,1441,1442],{},"Generator Pattern",[1444,1445,1446,1458,1469,1479],"tbody",{},[1431,1447,1448,1452,1455],{},[1449,1450,1451],"td",{},"Memory peak",[1449,1453,1454],{},"All segments in memory simultaneously",[1449,1456,1457],{},"Only currently processing segment in memory",[1431,1459,1460,1463,1466],{},[1449,1461,1462],{},"Applicable scenario",[1449,1464,1465],{},"Segment count \u003C 500",[1449,1467,1468],{},"Segment count > 500",[1431,1470,1471,1474,1477],{},[1449,1472,1473],{},"Progress tracking",[1449,1475,1476],{},"Known total, precise percentage",[1449,1478,1476],{},[1431,1480,1481,1484,1487],{},[1449,1482,1483],{},"Cancel response",[1449,1485,1486],{},"Must wait for current batch to complete",[1449,1488,1489],{},"Immediate response",[719,1491,1492,1493,782],{},"Engine automatically selects pattern based on segment count without user intervention. For actual scenarios of very large file downloads, see ",[772,1494,1495],{"href":112},"Live Replay Saving",[752,1497,1499],{"id":1498},"retry-mechanism","Retry Mechanism",[719,1501,1502],{},"When segment download fails, uses exponential backoff retry:",[741,1504,1506],{"className":818,"code":1505,"language":820,"meta":750,"style":750},"const downloadWithRetry = async (\n  segment: SegmentInfo,\n  maxRetries = 3\n): Promise\u003CArrayBuffer> => {\n  let lastError: unknown\n  for (let attempt = 0; attempt \u003C maxRetries; attempt++) {\n    try {\n      return await downloadAndDecryptSegment(segment)\n    } catch (e) {\n      lastError = e\n      if (attempt \u003C maxRetries - 1) {\n        \u002F\u002F Exponential backoff: 400ms, 800ms, 1600ms\n        await new Promise(r => setTimeout(r, Math.pow(2, attempt) * 400))\n      }\n    }\n  }\n  throw lastError\n}\n",[748,1507,1508,1521,1532,1542,1560,1572,1610,1617,1633,1650,1660,1684,1690,1742,1747,1751,1755,1763],{"__ignoreMap":750},[824,1509,1510,1512,1515,1517,1519],{"class":826,"line":827},[824,1511,831],{"class":830},[824,1513,1514],{"class":834}," downloadWithRetry ",[824,1516,839],{"class":838},[824,1518,842],{"class":830},[824,1520,845],{"class":834},[824,1522,1523,1526,1528,1530],{"class":826,"line":848},[824,1524,1525],{"class":851},"  segment",[824,1527,855],{"class":838},[824,1529,859],{"class":858},[824,1531,865],{"class":838},[824,1533,1534,1537,1539],{"class":826,"line":868},[824,1535,1536],{"class":834},"  maxRetries ",[824,1538,839],{"class":838},[824,1540,1541],{"class":954}," 3\n",[824,1543,1544,1546,1548,1550,1552,1554,1556,1558],{"class":826,"line":908},[824,1545,899],{"class":834},[824,1547,855],{"class":838},[824,1549,1192],{"class":858},[824,1551,1332],{"class":838},[824,1553,1335],{"class":858},[824,1555,1338],{"class":838},[824,1557,902],{"class":830},[824,1559,917],{"class":838},[824,1561,1562,1564,1567,1569],{"class":826,"line":920},[824,1563,964],{"class":830},[824,1565,1566],{"class":834}," lastError",[824,1568,855],{"class":838},[824,1570,1571],{"class":858}," unknown\n",[824,1573,1574,1576,1578,1581,1584,1586,1589,1592,1594,1596,1599,1601,1603,1606,1608],{"class":826,"line":961},[824,1575,1345],{"class":1004},[824,1577,877],{"class":940},[824,1579,1580],{"class":830},"let",[824,1582,1583],{"class":834}," attempt",[824,1585,929],{"class":838},[824,1587,1588],{"class":954}," 0",[824,1590,1591],{"class":838},";",[824,1593,1583],{"class":834},[824,1595,1013],{"class":838},[824,1597,1598],{"class":834}," maxRetries",[824,1600,1591],{"class":838},[824,1602,1583],{"class":834},[824,1604,1605],{"class":838},"++",[824,1607,911],{"class":940},[824,1609,1026],{"class":838},[824,1611,1612,1615],{"class":826,"line":975},[824,1613,1614],{"class":1004},"    try",[824,1616,917],{"class":838},[824,1618,1619,1622,1624,1627,1629,1631],{"class":826,"line":982},[824,1620,1621],{"class":1004},"      return",[824,1623,1054],{"class":1004},[824,1625,1626],{"class":871}," downloadAndDecryptSegment",[824,1628,941],{"class":940},[824,1630,1400],{"class":834},[824,1632,958],{"class":940},[824,1634,1635,1638,1641,1643,1646,1648],{"class":826,"line":1001},[824,1636,1637],{"class":838},"    }",[824,1639,1640],{"class":1004}," catch",[824,1642,877],{"class":940},[824,1644,1645],{"class":834},"e",[824,1647,911],{"class":940},[824,1649,1026],{"class":838},[824,1651,1652,1655,1657],{"class":826,"line":1029},[824,1653,1654],{"class":834},"      lastError",[824,1656,929],{"class":838},[824,1658,1659],{"class":834}," e\n",[824,1661,1662,1665,1667,1670,1672,1674,1677,1680,1682],{"class":826,"line":1044},[824,1663,1664],{"class":1004},"      if",[824,1666,877],{"class":940},[824,1668,1669],{"class":834},"attempt",[824,1671,1013],{"class":838},[824,1673,1598],{"class":834},[824,1675,1676],{"class":838}," -",[824,1678,1679],{"class":954}," 1",[824,1681,911],{"class":940},[824,1683,1026],{"class":838},[824,1685,1686],{"class":826,"line":1079},[824,1687,1689],{"class":1688},"sHwdD","        \u002F\u002F Exponential backoff: 400ms, 800ms, 1600ms\n",[824,1691,1692,1695,1698,1700,1702,1705,1707,1710,1712,1714,1716,1718,1720,1723,1725,1728,1730,1732,1734,1736,1739],{"class":826,"line":1095},[824,1693,1694],{"class":1004},"        await",[824,1696,1697],{"class":838}," new",[824,1699,1192],{"class":858},[824,1701,941],{"class":940},[824,1703,1704],{"class":851},"r",[824,1706,902],{"class":830},[824,1708,1709],{"class":871}," setTimeout",[824,1711,941],{"class":940},[824,1713,1704],{"class":834},[824,1715,888],{"class":838},[824,1717,932],{"class":834},[824,1719,782],{"class":838},[824,1721,1722],{"class":871},"pow",[824,1724,941],{"class":940},[824,1726,1727],{"class":954},"2",[824,1729,888],{"class":838},[824,1731,1583],{"class":834},[824,1733,911],{"class":940},[824,1735,1293],{"class":838},[824,1737,1738],{"class":954}," 400",[824,1740,1741],{"class":940},"))\n",[824,1743,1744],{"class":826,"line":1101},[824,1745,1746],{"class":838},"      }\n",[824,1748,1749],{"class":826,"line":1107},[824,1750,1098],{"class":838},[824,1752,1753],{"class":826,"line":1112},[824,1754,1104],{"class":838},[824,1756,1757,1760],{"class":826,"line":1133},[824,1758,1759],{"class":1004},"  throw",[824,1761,1762],{"class":834}," lastError\n",[824,1764,1765],{"class":826,"line":1167},[824,1766,1210],{"class":838},[719,1768,1769,855],{},[1214,1770,1771],{},"Retry Strategy",[1425,1773,1774,1787],{},[1428,1775,1776],{},[1431,1777,1778,1781,1784],{},[1434,1779,1780],{},"Attempt #",[1434,1782,1783],{},"Delay",[1434,1785,1786],{},"Cumulative Wait",[1444,1788,1789,1799,1810],{},[1431,1790,1791,1794,1797],{},[1449,1792,1793],{},"1st failure",[1449,1795,1796],{},"400ms",[1449,1798,1796],{},[1431,1800,1801,1804,1807],{},[1449,1802,1803],{},"2nd failure",[1449,1805,1806],{},"800ms",[1449,1808,1809],{},"1200ms",[1431,1811,1812,1815,1818],{},[1449,1813,1814],{},"3rd failure",[1449,1816,1817],{},"1600ms",[1449,1819,1820],{},"2800ms",[719,1822,1823,855],{},[1214,1824,1825],{},"Cases that don't trigger retry",[1218,1827,1828,1831,1834],{},[1221,1829,1830],{},"HTTP 4xx client errors (403, 404, etc.) — retry meaningless",[1221,1832,1833],{},"CORS errors — policy issue, retry won't change result",[1221,1835,1836],{},"Unsupported encryption error — cannot be resolved via retry",[766,1838,1839],{},[719,1840,1841,1842,1846,1847,782],{},"Retry mechanism works together with error classification table in ",[772,1843,1845],{"href":1844},"\u002Fdocs\u002Fadvanced\u002Fonline-tools#error-handling","Online Tools — Error Handling",". HTTP 4xx and CORS errors thrown directly, displayed as corresponding user prompts by upper UI layer. For troubleshooting mid-download failures, see ",[772,1848,1850],{"href":1849},"\u002Fdocs\u002Ftroubleshooting\u002Fcommon-issues#mid-download-failure","Common Issues Troubleshooting — Mid-Download Failure",[752,1852,1854],{"id":1853},"error-classification","Error Classification",[741,1856,1858],{"className":818,"code":1857,"language":820,"meta":750,"style":750},"class FetchError extends Error {\n  constructor(\n    message: string,\n    public status: number,\n    public url: string\n  ) {\n    super(message)\n    this.name = 'FetchError'\n  }\n}\n",[748,1859,1860,1876,1883,1895,1909,1921,1928,1940,1960,1964],{"__ignoreMap":750},[824,1861,1862,1865,1868,1871,1874],{"class":826,"line":827},[824,1863,1864],{"class":830},"class",[824,1866,1867],{"class":858}," FetchError",[824,1869,1870],{"class":830}," extends",[824,1872,1873],{"class":858}," Error",[824,1875,917],{"class":838},[824,1877,1878,1881],{"class":826,"line":848},[824,1879,1880],{"class":830},"  constructor",[824,1882,1130],{"class":838},[824,1884,1885,1888,1890,1893],{"class":826,"line":868},[824,1886,1887],{"class":851},"    message",[824,1889,855],{"class":838},[824,1891,1892],{"class":858}," string",[824,1894,865],{"class":838},[824,1896,1897,1900,1903,1905,1907],{"class":826,"line":908},[824,1898,1899],{"class":830},"    public",[824,1901,1902],{"class":851}," status",[824,1904,855],{"class":838},[824,1906,896],{"class":858},[824,1908,865],{"class":838},[824,1910,1911,1913,1916,1918],{"class":826,"line":920},[824,1912,1899],{"class":830},[824,1914,1915],{"class":851}," url",[824,1917,855],{"class":838},[824,1919,1920],{"class":858}," string\n",[824,1922,1923,1926],{"class":826,"line":961},[824,1924,1925],{"class":838},"  )",[824,1927,917],{"class":838},[824,1929,1930,1933,1935,1938],{"class":826,"line":975},[824,1931,1932],{"class":834},"    super",[824,1934,941],{"class":940},[824,1936,1937],{"class":834},"message",[824,1939,958],{"class":940},[824,1941,1942,1945,1948,1950,1953,1957],{"class":826,"line":982},[824,1943,1944],{"class":838},"    this.",[824,1946,1947],{"class":834},"name",[824,1949,929],{"class":838},[824,1951,1952],{"class":838}," '",[824,1954,1956],{"class":1955},"sfazB","FetchError",[824,1958,1959],{"class":838},"'\n",[824,1961,1962],{"class":826,"line":1001},[824,1963,1104],{"class":838},[824,1965,1966],{"class":826,"line":1029},[824,1967,1210],{"class":838},[719,1969,1970],{},"Errors classified and handled by HTTP status code:",[1425,1972,1973,1986],{},[1428,1974,1975],{},[1431,1976,1977,1980,1983],{},[1434,1978,1979],{},"Status Code",[1434,1981,1982],{},"Error Type",[1434,1984,1985],{},"User Prompt",[1444,1987,1988,1999,2010,2021,2032],{},[1431,1989,1990,1993,1996],{},[1449,1991,1992],{},"403",[1449,1994,1995],{},"Auth\u002Fauthorization failure",[1449,1997,1998],{},"\"Access denied, please check if URL is valid\"",[1431,2000,2001,2004,2007],{},[1449,2002,2003],{},"404",[1449,2005,2006],{},"Resource not found",[1449,2008,2009],{},"\"Segment not found, stream may have expired\"",[1431,2011,2012,2015,2018],{},[1449,2013,2014],{},"502\u002F503\u002F504",[1449,2016,2017],{},"Server error",[1449,2019,2020],{},"\"Server temporarily unavailable, please try again later\"",[1431,2022,2023,2026,2029],{},[1449,2024,2025],{},"CORS",[1449,2027,2028],{},"Cross-origin restriction",[1449,2030,2031],{},"\"Cross-origin request blocked, recommend using extension version\"",[1431,2033,2034,2037,2040],{},[1449,2035,2036],{},"Network",[1449,2038,2039],{},"Network interruption",[1449,2041,2042],{},"\"Network connection failed, please check network\"",[1255,2044,2045],{},[719,2046,2047,2048,2051,2052,2055,2056,2058,2059,782],{},"When encountering CORS errors, recommend installing ",[772,2049,2050],{"href":19},"browser extension",", which can bypass same-origin policy via ",[748,2053,2054],{},"webRequest"," permissions. See ",[772,2057,141],{"href":142}," for more troubleshooting methods. For CORS technical principles and limitations, see ",[772,2060,2062],{"href":2061},"\u002Fdocs\u002Ftroubleshooting\u002Fknown-issues#browser-limitations","Known Limitations — Browser Limitations",[733,2064,2066],{"id":2065},"segment-processing-module","Segment Processing Module",[752,2068,2070],{"id":2069},"aes-128-decryption","AES-128 Decryption",[719,2072,2073],{},"For encrypted HLS streams, FlowPick uses Web Crypto API to decrypt in browser:",[741,2075,2077],{"className":818,"code":2076,"language":820,"meta":750,"style":750},"const decryptAES128 = async (\n  encryptedData: ArrayBuffer,\n  key: ArrayBuffer,\n  iv?: Uint8Array\n): Promise\u003CArrayBuffer> => {\n  const keyBytes = await crypto.subtle.importKey(\n    'raw', key,\n    { name: 'AES-CBC' },\n    false,\n    ['decrypt']\n  )\n\n  const ivBuffer = iv ? new Uint8Array(iv) : new Uint8Array(16)\n\n  const decrypted = await crypto.subtle.decrypt(\n    { name: 'AES-CBC', iv: ivBuffer },\n    keyBytes,\n    encryptedData\n  )\n\n  return decrypted\n}\n",[748,2078,2079,2092,2103,2114,2124,2142,2168,2186,2205,2213,2228,2232,2236,2276,2280,2303,2327,2334,2339,2343,2347,2355],{"__ignoreMap":750},[824,2080,2081,2083,2086,2088,2090],{"class":826,"line":827},[824,2082,831],{"class":830},[824,2084,2085],{"class":834}," decryptAES128 ",[824,2087,839],{"class":838},[824,2089,842],{"class":830},[824,2091,845],{"class":834},[824,2093,2094,2097,2099,2101],{"class":826,"line":848},[824,2095,2096],{"class":851},"  encryptedData",[824,2098,855],{"class":838},[824,2100,885],{"class":858},[824,2102,865],{"class":838},[824,2104,2105,2108,2110,2112],{"class":826,"line":868},[824,2106,2107],{"class":851},"  key",[824,2109,855],{"class":838},[824,2111,885],{"class":858},[824,2113,865],{"class":838},[824,2115,2116,2119,2121],{"class":826,"line":908},[824,2117,2118],{"class":851},"  iv",[824,2120,1318],{"class":838},[824,2122,2123],{"class":858}," Uint8Array\n",[824,2125,2126,2128,2130,2132,2134,2136,2138,2140],{"class":826,"line":920},[824,2127,899],{"class":834},[824,2129,855],{"class":838},[824,2131,1192],{"class":858},[824,2133,1332],{"class":838},[824,2135,1335],{"class":858},[824,2137,1338],{"class":838},[824,2139,902],{"class":830},[824,2141,917],{"class":838},[824,2143,2144,2146,2149,2151,2153,2156,2158,2161,2163,2166],{"class":826,"line":961},[824,2145,923],{"class":830},[824,2147,2148],{"class":834}," keyBytes",[824,2150,929],{"class":838},[824,2152,1054],{"class":1004},[824,2154,2155],{"class":834}," crypto",[824,2157,782],{"class":838},[824,2159,2160],{"class":834},"subtle",[824,2162,782],{"class":838},[824,2164,2165],{"class":871},"importKey",[824,2167,1130],{"class":940},[824,2169,2170,2173,2176,2179,2181,2184],{"class":826,"line":975},[824,2171,2172],{"class":838},"    '",[824,2174,2175],{"class":1955},"raw",[824,2177,2178],{"class":838},"'",[824,2180,888],{"class":838},[824,2182,2183],{"class":834}," key",[824,2185,865],{"class":838},[824,2187,2188,2190,2193,2195,2197,2200,2202],{"class":826,"line":982},[824,2189,1136],{"class":838},[824,2191,2192],{"class":940}," name",[824,2194,855],{"class":838},[824,2196,1952],{"class":838},[824,2198,2199],{"class":1955},"AES-CBC",[824,2201,2178],{"class":838},[824,2203,2204],{"class":838}," },\n",[824,2206,2207,2211],{"class":826,"line":1001},[824,2208,2210],{"class":2209},"sfNiH","    false",[824,2212,865],{"class":838},[824,2214,2215,2218,2220,2223,2225],{"class":826,"line":1029},[824,2216,2217],{"class":940},"    [",[824,2219,2178],{"class":838},[824,2221,2222],{"class":1955},"decrypt",[824,2224,2178],{"class":838},[824,2226,2227],{"class":940},"]\n",[824,2229,2230],{"class":826,"line":1044},[824,2231,1183],{"class":940},[824,2233,2234],{"class":826,"line":1079},[824,2235,979],{"emptyLinePlaceholder":978},[824,2237,2238,2240,2243,2245,2248,2251,2253,2256,2258,2261,2263,2265,2267,2269,2271,2274],{"class":826,"line":1095},[824,2239,923],{"class":830},[824,2241,2242],{"class":834}," ivBuffer",[824,2244,929],{"class":838},[824,2246,2247],{"class":834}," iv",[824,2249,2250],{"class":838}," ?",[824,2252,1697],{"class":838},[824,2254,2255],{"class":871}," Uint8Array",[824,2257,941],{"class":940},[824,2259,2260],{"class":834},"iv",[824,2262,911],{"class":940},[824,2264,855],{"class":838},[824,2266,1697],{"class":838},[824,2268,2255],{"class":871},[824,2270,941],{"class":940},[824,2272,2273],{"class":954},"16",[824,2275,958],{"class":940},[824,2277,2278],{"class":826,"line":1101},[824,2279,979],{"emptyLinePlaceholder":978},[824,2281,2282,2284,2287,2289,2291,2293,2295,2297,2299,2301],{"class":826,"line":1107},[824,2283,923],{"class":830},[824,2285,2286],{"class":834}," decrypted",[824,2288,929],{"class":838},[824,2290,1054],{"class":1004},[824,2292,2155],{"class":834},[824,2294,782],{"class":838},[824,2296,2160],{"class":834},[824,2298,782],{"class":838},[824,2300,2222],{"class":871},[824,2302,1130],{"class":940},[824,2304,2305,2307,2309,2311,2313,2315,2317,2319,2321,2323,2325],{"class":826,"line":1112},[824,2306,1136],{"class":838},[824,2308,2192],{"class":940},[824,2310,855],{"class":838},[824,2312,1952],{"class":838},[824,2314,2199],{"class":1955},[824,2316,2178],{"class":838},[824,2318,888],{"class":838},[824,2320,2247],{"class":940},[824,2322,855],{"class":838},[824,2324,2242],{"class":834},[824,2326,2204],{"class":838},[824,2328,2329,2332],{"class":826,"line":1133},[824,2330,2331],{"class":834},"    keyBytes",[824,2333,865],{"class":838},[824,2335,2336],{"class":826,"line":1167},[824,2337,2338],{"class":834},"    encryptedData\n",[824,2340,2341],{"class":826,"line":1180},[824,2342,1183],{"class":940},[824,2344,2345],{"class":826,"line":1186},[824,2346,979],{"emptyLinePlaceholder":978},[824,2348,2349,2352],{"class":826,"line":1207},[824,2350,2351],{"class":1004},"  return",[824,2353,2354],{"class":834}," decrypted\n",[824,2356,2358],{"class":826,"line":2357},22,[824,2359,1210],{"class":838},[719,2361,2362,855],{},[1214,2363,2364],{},"Decryption Flow",[2366,2367,2368,2375,2378,2381],"ol",{},[1221,2369,2370,2371,2374],{},"Extract key URI and IV from M3U8's ",[748,2372,2373],{},"#EXT-X-KEY"," tag",[1221,2376,2377],{},"Download key file (usually 16-byte binary file)",[1221,2379,2380],{},"Decrypt each segment using AES-128-CBC mode",[1221,2382,2383],{},"If IV not specified, use segment sequence number as IV (HLS spec default behavior)",[719,2385,2386,855],{},[1214,2387,2388],{},"Performance Considerations",[1218,2390,2391,2394,2397],{},[1221,2392,2393],{},"Web Crypto API uses hardware acceleration, decryption speed usually not bottleneck",[1221,2395,2396],{},"Each segment decrypted independently, can parallelize with download",[1221,2398,2399],{},"Key only needs to be downloaded once, cached in memory",[766,2401,2402],{},[719,2403,2404,2405,2409,2410,2412,2413,782],{},"All decryption operations completed locally in browser; keys and segment data not uploaded to any server. For more details on encryption detection, see ",[772,2406,2408],{"href":2407},"\u002Fdocs\u002Ffeatures\u002Fvideo-sniffing#encrypted-streams-aes-128","Video Sniffing — Encrypted Streams",". For privacy protection strategy, see ",[772,2411,55],{"href":56},". For unsupported encryption types (Widevine, PlayReady etc.), see ",[772,2414,2416],{"href":2415},"\u002Fdocs\u002Ftroubleshooting\u002Fknown-issues#drm-protected-content","Known Limitations — DRM Protected Content",[752,2418,2420],{"id":2419},"ts-segment-concatenation","TS Segment Concatenation",[719,2422,2423],{},"For TS output format, segments directly concatenated in binary:",[741,2425,2427],{"className":818,"code":2426,"language":820,"meta":750,"style":750},"\u002F\u002F Pseudocode\nconst merged = new Uint8Array(totalSize)\nlet offset = 0\nfor (const segment of segments) {\n  merged.set(new Uint8Array(segment), offset)\n  offset += segment.byteLength\n}\n",[748,2428,2429,2434,2450,2461,2481,2511,2526],{"__ignoreMap":750},[824,2430,2431],{"class":826,"line":827},[824,2432,2433],{"class":1688},"\u002F\u002F Pseudocode\n",[824,2435,2436,2438,2441,2443,2445,2447],{"class":826,"line":848},[824,2437,831],{"class":830},[824,2439,2440],{"class":834}," merged ",[824,2442,839],{"class":838},[824,2444,1697],{"class":838},[824,2446,2255],{"class":871},[824,2448,2449],{"class":834},"(totalSize)\n",[824,2451,2452,2454,2457,2459],{"class":826,"line":868},[824,2453,1580],{"class":830},[824,2455,2456],{"class":834}," offset ",[824,2458,839],{"class":838},[824,2460,972],{"class":954},[824,2462,2463,2466,2468,2470,2473,2476,2479],{"class":826,"line":908},[824,2464,2465],{"class":1004},"for",[824,2467,877],{"class":834},[824,2469,831],{"class":830},[824,2471,2472],{"class":834}," segment ",[824,2474,2475],{"class":838},"of",[824,2477,2478],{"class":834}," segments) ",[824,2480,1026],{"class":838},[824,2482,2483,2486,2488,2491,2493,2496,2498,2500,2502,2504,2506,2509],{"class":826,"line":920},[824,2484,2485],{"class":834},"  merged",[824,2487,782],{"class":838},[824,2489,2490],{"class":871},"set",[824,2492,941],{"class":940},[824,2494,2495],{"class":838},"new",[824,2497,2255],{"class":871},[824,2499,941],{"class":940},[824,2501,1400],{"class":834},[824,2503,899],{"class":940},[824,2505,888],{"class":838},[824,2507,2508],{"class":834}," offset",[824,2510,958],{"class":940},[824,2512,2513,2516,2519,2521,2523],{"class":826,"line":961},[824,2514,2515],{"class":834},"  offset",[824,2517,2518],{"class":838}," +=",[824,2520,1352],{"class":834},[824,2522,782],{"class":838},[824,2524,2525],{"class":834},"byteLength\n",[824,2527,2528],{"class":826,"line":975},[824,2529,1210],{"class":838},[719,2531,2532],{},"This approach has zero CPU overhead, speed limited only by memory copy speed.",[752,2534,2536],{"id":2535},"ffmpeg-wasm-remuxing","FFmpeg WASM Remuxing",[719,2538,2539,2540,2542],{},"For MP4 output format, use FFmpeg WASM for container conversion. See ",[772,2541,60],{"href":61}," document for details.",[1255,2544,2545],{},[719,2546,2547,2548,782],{},"If you only need TS format, selecting TS output can completely bypass FFmpeg, significantly improving merge speed. TS files can be played directly with VLC, PotPlayer etc. For output format selection recommendations, see ",[772,2549,2551],{"href":2550},"\u002Fdocs\u002Ffeatures\u002Fformat-conversion#output-format-selection-guide","Format Conversion — Output Format Selection",[752,2553,2555],{"id":2554},"dash-stream-special-processing","DASH Stream Special Processing",[719,2557,2558],{},"DASH streams differ significantly from HLS streams in segment processing:",[741,2560,2563],{"className":2561,"code":2562,"language":746},[744],"HLS stream processing:\n  Segment 0 → Segment 1 → Segment 2 → ... → Concat → Output\n\nDASH stream processing (audio-video separated):\n  Init segment → Video Seg 0 → Video Seg 1 → ... ─┐\n                                              ├→ FFmpeg Merge → Output\n  Init segment → Audio Seg 0 → Audio Seg 1 → ... ─┘\n",[748,2564,2562],{"__ignoreMap":750},[719,2566,2567],{},"DASH's FMP4 (Fragmented MP4) format requires special handling:",[2366,2569,2570,2583,2595],{},[1221,2571,2572,877,2575,2578,2579,2582],{},[1214,2573,2574],{},"Init segment",[748,2576,2577],{},"ftyp"," + ",[748,2580,2581],{},"moov"," box) must be placed at beginning of file",[1221,2584,2585,877,2588,2578,2591,2594],{},[1214,2586,2587],{},"Media segments",[748,2589,2590],{},"moof",[748,2592,2593],{},"mdat"," box) appended sequentially",[1221,2596,2597],{},"When audio-video separated, need to download video and audio tracks separately, finally merge via FFmpeg",[766,2599,2600],{},[719,2601,2602,2603,2607,2608,2611,2612,782],{},"For DASH stream manifest parsing details, see ",[772,2604,2606],{"href":2605},"\u002Fdocs\u002Ffeatures\u002Fvideo-sniffing#dashmpd-streams","Video Sniffing — DASH Streams",". For specific FMP4 reassembly implementation, see ",[772,2609,2610],{"href":61},"Format Conversion — FMP4 Reassembly",". For known issues with DASH audio-video separation, see ",[772,2613,2615],{"href":2614},"\u002Fdocs\u002Ftroubleshooting\u002Fknown-issues#separated-audio-video-streams","Known Limitations — Separated Audio-Video Streams",[733,2617,2619],{"id":2618},"file-writing-module","File Writing Module",[719,2621,2622],{},"Writing module selects strategy by priority to ensure working across as many browsers as possible.",[719,2624,2625],{},[725,2626],{"alt":2627,"src":2628},"Three-Tier Write Strategy Comparison","\u002Fscreenshots\u002Fwrite-strategies.png",[752,2630,2632],{"id":2631},"strategy-1-file-system-access-api-optimal","Strategy 1: File System Access API (Optimal)",[741,2634,2636],{"className":818,"code":2635,"language":820,"meta":750,"style":750},"async function createFSAStream(\n  filename: string,\n  dirHandle?: FileSystemDirectoryHandle | null\n): Promise\u003CWritableStream\u003CUint8Array>> {\n  let handle: FileSystemFileHandle\n\n  if (dirHandle) {\n    \u002F\u002F Already have directory permission, directly create file\n    handle = await dirHandle.getFileHandle(filename, { create: true })\n  } else {\n    \u002F\u002F Popup for user to choose save location\n    handle = await window.showSaveFilePicker!({\n      suggestedName: filename,\n      types: [{\n        description: 'Video',\n        accept: { 'video\u002Fmp4': ['.mp4'] }\n      }]\n    })\n  }\n\n  const writable = await handle.createWritable()\n\n  return new WritableStream\u003CUint8Array>({\n    async write(chunk) { await writable.write(chunk) },\n    async close() { await writable.close() },\n    async abort(reason) { await writable.abort(reason) }\n  }, {\n    highWaterMark: 16 * 1024 * 1024 \u002F\u002F 16MB buffer\n  })\n}\n",[748,2637,2638,2649,2660,2676,2697,2709,2713,2727,2732,2772,2782,2787,2809,2821,2833,2849,2881,2888,2894,2898,2902,2922,2926,2946,2981,3008,3042,3050,3074,3081],{"__ignoreMap":750},[824,2639,2640,2642,2644,2647],{"class":826,"line":827},[824,2641,1287],{"class":830},[824,2643,1290],{"class":830},[824,2645,2646],{"class":871}," createFSAStream",[824,2648,1130],{"class":838},[824,2650,2651,2654,2656,2658],{"class":826,"line":848},[824,2652,2653],{"class":851},"  filename",[824,2655,855],{"class":838},[824,2657,1892],{"class":858},[824,2659,865],{"class":838},[824,2661,2662,2665,2667,2670,2673],{"class":826,"line":868},[824,2663,2664],{"class":851},"  dirHandle",[824,2666,1318],{"class":838},[824,2668,2669],{"class":858}," FileSystemDirectoryHandle",[824,2671,2672],{"class":838}," |",[824,2674,2675],{"class":858}," null\n",[824,2677,2678,2680,2682,2684,2687,2689,2692,2695],{"class":826,"line":908},[824,2679,1326],{"class":838},[824,2681,1192],{"class":858},[824,2683,1332],{"class":838},[824,2685,2686],{"class":858},"WritableStream",[824,2688,1332],{"class":838},[824,2690,2691],{"class":858},"Uint8Array",[824,2693,2694],{"class":838},">>",[824,2696,917],{"class":838},[824,2698,2699,2701,2704,2706],{"class":826,"line":920},[824,2700,964],{"class":830},[824,2702,2703],{"class":834}," handle",[824,2705,855],{"class":838},[824,2707,2708],{"class":858}," FileSystemFileHandle\n",[824,2710,2711],{"class":826,"line":961},[824,2712,979],{"emptyLinePlaceholder":978},[824,2714,2715,2718,2720,2723,2725],{"class":826,"line":975},[824,2716,2717],{"class":1004},"  if",[824,2719,877],{"class":940},[824,2721,2722],{"class":834},"dirHandle",[824,2724,911],{"class":940},[824,2726,1026],{"class":838},[824,2728,2729],{"class":826,"line":982},[824,2730,2731],{"class":1688},"    \u002F\u002F Already have directory permission, directly create file\n",[824,2733,2734,2737,2739,2741,2744,2746,2749,2751,2754,2756,2759,2762,2764,2767,2770],{"class":826,"line":1001},[824,2735,2736],{"class":834},"    handle",[824,2738,929],{"class":838},[824,2740,1054],{"class":1004},[824,2742,2743],{"class":834}," dirHandle",[824,2745,782],{"class":838},[824,2747,2748],{"class":871},"getFileHandle",[824,2750,941],{"class":940},[824,2752,2753],{"class":834},"filename",[824,2755,888],{"class":838},[824,2757,2758],{"class":838}," {",[824,2760,2761],{"class":940}," create",[824,2763,855],{"class":838},[824,2765,2766],{"class":2209}," true",[824,2768,2769],{"class":838}," }",[824,2771,958],{"class":940},[824,2773,2774,2777,2780],{"class":826,"line":1029},[824,2775,2776],{"class":838},"  }",[824,2778,2779],{"class":1004}," else",[824,2781,917],{"class":838},[824,2783,2784],{"class":826,"line":1044},[824,2785,2786],{"class":1688},"    \u002F\u002F Popup for user to choose save location\n",[824,2788,2789,2791,2793,2795,2798,2800,2803,2805,2807],{"class":826,"line":1079},[824,2790,2736],{"class":834},[824,2792,929],{"class":838},[824,2794,1054],{"class":1004},[824,2796,2797],{"class":834}," window",[824,2799,782],{"class":838},[824,2801,2802],{"class":871},"showSaveFilePicker",[824,2804,1074],{"class":838},[824,2806,941],{"class":940},[824,2808,1026],{"class":838},[824,2810,2811,2814,2816,2819],{"class":826,"line":1095},[824,2812,2813],{"class":940},"      suggestedName",[824,2815,855],{"class":838},[824,2817,2818],{"class":834}," filename",[824,2820,865],{"class":838},[824,2822,2823,2826,2828,2831],{"class":826,"line":1101},[824,2824,2825],{"class":940},"      types",[824,2827,855],{"class":838},[824,2829,2830],{"class":940}," [",[824,2832,1026],{"class":838},[824,2834,2835,2838,2840,2842,2845,2847],{"class":826,"line":1107},[824,2836,2837],{"class":940},"        description",[824,2839,855],{"class":838},[824,2841,1952],{"class":838},[824,2843,2844],{"class":1955},"Video",[824,2846,2178],{"class":838},[824,2848,865],{"class":838},[824,2850,2851,2854,2856,2858,2860,2863,2865,2867,2869,2871,2874,2876,2879],{"class":826,"line":1112},[824,2852,2853],{"class":940},"        accept",[824,2855,855],{"class":838},[824,2857,2758],{"class":838},[824,2859,1952],{"class":838},[824,2861,2862],{"class":940},"video\u002Fmp4",[824,2864,2178],{"class":838},[824,2866,855],{"class":838},[824,2868,2830],{"class":940},[824,2870,2178],{"class":838},[824,2872,2873],{"class":1955},".mp4",[824,2875,2178],{"class":838},[824,2877,2878],{"class":940},"] ",[824,2880,1210],{"class":838},[824,2882,2883,2886],{"class":826,"line":1133},[824,2884,2885],{"class":838},"      }",[824,2887,2227],{"class":940},[824,2889,2890,2892],{"class":826,"line":1167},[824,2891,1637],{"class":838},[824,2893,958],{"class":940},[824,2895,2896],{"class":826,"line":1180},[824,2897,1104],{"class":838},[824,2899,2900],{"class":826,"line":1186},[824,2901,979],{"emptyLinePlaceholder":978},[824,2903,2904,2906,2909,2911,2913,2915,2917,2920],{"class":826,"line":1207},[824,2905,923],{"class":830},[824,2907,2908],{"class":834}," writable",[824,2910,929],{"class":838},[824,2912,1054],{"class":1004},[824,2914,2703],{"class":834},[824,2916,782],{"class":838},[824,2918,2919],{"class":871},"createWritable",[824,2921,1177],{"class":940},[824,2923,2924],{"class":826,"line":2357},[824,2925,979],{"emptyLinePlaceholder":978},[824,2927,2929,2931,2933,2936,2938,2940,2942,2944],{"class":826,"line":2928},23,[824,2930,2351],{"class":1004},[824,2932,1697],{"class":838},[824,2934,2935],{"class":871}," WritableStream",[824,2937,1332],{"class":838},[824,2939,2691],{"class":858},[824,2941,1338],{"class":838},[824,2943,941],{"class":940},[824,2945,1026],{"class":838},[824,2947,2949,2952,2955,2957,2960,2962,2964,2966,2968,2970,2973,2975,2977,2979],{"class":826,"line":2948},24,[824,2950,2951],{"class":830},"    async",[824,2953,2954],{"class":940}," write",[824,2956,941],{"class":838},[824,2958,2959],{"class":851},"chunk",[824,2961,899],{"class":838},[824,2963,2758],{"class":838},[824,2965,1054],{"class":1004},[824,2967,2908],{"class":834},[824,2969,782],{"class":838},[824,2971,2972],{"class":871},"write",[824,2974,941],{"class":940},[824,2976,2959],{"class":834},[824,2978,911],{"class":940},[824,2980,1164],{"class":838},[824,2982,2984,2986,2989,2992,2994,2996,2998,3000,3003,3006],{"class":826,"line":2983},25,[824,2985,2951],{"class":830},[824,2987,2988],{"class":940}," close",[824,2990,2991],{"class":838},"()",[824,2993,2758],{"class":838},[824,2995,1054],{"class":1004},[824,2997,2908],{"class":834},[824,2999,782],{"class":838},[824,3001,3002],{"class":871},"close",[824,3004,3005],{"class":940},"() ",[824,3007,1164],{"class":838},[824,3009,3011,3013,3016,3018,3021,3023,3025,3027,3029,3031,3034,3036,3038,3040],{"class":826,"line":3010},26,[824,3012,2951],{"class":830},[824,3014,3015],{"class":940}," abort",[824,3017,941],{"class":838},[824,3019,3020],{"class":851},"reason",[824,3022,899],{"class":838},[824,3024,2758],{"class":838},[824,3026,1054],{"class":1004},[824,3028,2908],{"class":834},[824,3030,782],{"class":838},[824,3032,3033],{"class":871},"abort",[824,3035,941],{"class":940},[824,3037,3020],{"class":834},[824,3039,911],{"class":940},[824,3041,1210],{"class":838},[824,3043,3045,3048],{"class":826,"line":3044},27,[824,3046,3047],{"class":838},"  },",[824,3049,917],{"class":838},[824,3051,3053,3056,3058,3061,3064,3067,3069,3071],{"class":826,"line":3052},28,[824,3054,3055],{"class":940},"    highWaterMark",[824,3057,855],{"class":838},[824,3059,3060],{"class":954}," 16",[824,3062,3063],{"class":838}," *",[824,3065,3066],{"class":954}," 1024",[824,3068,3063],{"class":838},[824,3070,3066],{"class":954},[824,3072,3073],{"class":1688}," \u002F\u002F 16MB buffer\n",[824,3075,3077,3079],{"class":826,"line":3076},29,[824,3078,2776],{"class":838},[824,3080,958],{"class":940},[824,3082,3084],{"class":826,"line":3083},30,[824,3085,1210],{"class":838},[719,3087,3088,855],{},[1214,3089,3090],{},"Advantages",[1218,3092,3093,3096,3099],{},[1221,3094,3095],{},"Streaming write, constant memory usage (only 16MB buffer)",[1221,3097,3098],{},"Supports arbitrary file sizes",[1221,3100,3101],{},"After directory persistence, no repeated popups needed",[719,3103,3104,855],{},[1214,3105,3106],{},"Limitations",[1218,3108,3109,3112],{},[1221,3110,3111],{},"Only supported on Chrome 86+ and Edge 86+",[1221,3113,3114,3115,3118],{},"Requires user gesture trigger (",[748,3116,3117],{},"showDirectoryPicker"," must be called within user click event)",[752,3120,3122],{"id":3121},"strategy-2-streamsaverjs-alternative","Strategy 2: StreamSaver.js (Alternative)",[741,3124,3126],{"className":818,"code":3125,"language":820,"meta":750,"style":750},"async function createStreamSaverStream(\n  filename: string,\n  fileSize?: number\n): Promise\u003CWritableStream\u003CUint8Array>> {\n  const ss = await getStreamSaver()\n  const fileStream = ss.createWriteStream(filename, { size: fileSize })\n  return fileStream\n}\n",[748,3127,3128,3139,3149,3159,3177,3193,3229,3236],{"__ignoreMap":750},[824,3129,3130,3132,3134,3137],{"class":826,"line":827},[824,3131,1287],{"class":830},[824,3133,1290],{"class":830},[824,3135,3136],{"class":871}," createStreamSaverStream",[824,3138,1130],{"class":838},[824,3140,3141,3143,3145,3147],{"class":826,"line":848},[824,3142,2653],{"class":851},[824,3144,855],{"class":838},[824,3146,1892],{"class":858},[824,3148,865],{"class":838},[824,3150,3151,3154,3156],{"class":826,"line":868},[824,3152,3153],{"class":851},"  fileSize",[824,3155,1318],{"class":838},[824,3157,3158],{"class":858}," number\n",[824,3160,3161,3163,3165,3167,3169,3171,3173,3175],{"class":826,"line":908},[824,3162,1326],{"class":838},[824,3164,1192],{"class":858},[824,3166,1332],{"class":838},[824,3168,2686],{"class":858},[824,3170,1332],{"class":838},[824,3172,2691],{"class":858},[824,3174,2694],{"class":838},[824,3176,917],{"class":838},[824,3178,3179,3181,3184,3186,3188,3191],{"class":826,"line":920},[824,3180,923],{"class":830},[824,3182,3183],{"class":834}," ss",[824,3185,929],{"class":838},[824,3187,1054],{"class":1004},[824,3189,3190],{"class":871}," getStreamSaver",[824,3192,1177],{"class":940},[824,3194,3195,3197,3200,3202,3204,3206,3209,3211,3213,3215,3217,3220,3222,3225,3227],{"class":826,"line":961},[824,3196,923],{"class":830},[824,3198,3199],{"class":834}," fileStream",[824,3201,929],{"class":838},[824,3203,3183],{"class":834},[824,3205,782],{"class":838},[824,3207,3208],{"class":871},"createWriteStream",[824,3210,941],{"class":940},[824,3212,2753],{"class":834},[824,3214,888],{"class":838},[824,3216,2758],{"class":838},[824,3218,3219],{"class":940}," size",[824,3221,855],{"class":838},[824,3223,3224],{"class":834}," fileSize",[824,3226,2769],{"class":838},[824,3228,958],{"class":940},[824,3230,3231,3233],{"class":826,"line":975},[824,3232,2351],{"class":1004},[824,3234,3235],{"class":834}," fileStream\n",[824,3237,3238],{"class":826,"line":982},[824,3239,1210],{"class":838},[719,3241,3242,855],{},[1214,3243,3090],{},[1218,3245,3246,3249],{},[1221,3247,3248],{},"Streaming write, low memory usage",[1221,3250,3251],{},"Better compatibility than FSA API",[719,3253,3254,855],{},[1214,3255,3106],{},[1218,3257,3258,3261,3272],{},[1221,3259,3260],{},"Requires Service Worker support",[1221,3262,3263,3264,3267,3268,3271],{},"Requires ",[748,3265,3266],{},"mitm.html"," and ",[748,3269,3270],{},"streamsaver-sw.js"," properly deployed",[1221,3273,3274],{},"Some enterprise network environments may block Service Worker",[752,3276,3278],{"id":3277},"strategy-3-blob-fallback","Strategy 3: Blob Fallback",[741,3280,3282],{"className":818,"code":3281,"language":820,"meta":750,"style":750},"\u002F\u002F Pseudocode\nconst blob = new Blob([mergedData], { type: 'video\u002Fmp4' })\nconst url = URL.createObjectURL(blob)\nconst a = document.createElement('a')\na.href = url\na.download = filename\na.click()\nURL.revokeObjectURL(url)\n",[748,3283,3284,3288,3324,3344,3371,3385,3399,3410],{"__ignoreMap":750},[824,3285,3286],{"class":826,"line":827},[824,3287,2433],{"class":1688},[824,3289,3290,3292,3295,3297,3299,3302,3305,3307,3309,3312,3314,3316,3318,3320,3322],{"class":826,"line":848},[824,3291,831],{"class":830},[824,3293,3294],{"class":834}," blob ",[824,3296,839],{"class":838},[824,3298,1697],{"class":838},[824,3300,3301],{"class":871}," Blob",[824,3303,3304],{"class":834},"([mergedData]",[824,3306,888],{"class":838},[824,3308,2758],{"class":838},[824,3310,3311],{"class":940}," type",[824,3313,855],{"class":838},[824,3315,1952],{"class":838},[824,3317,2862],{"class":1955},[824,3319,2178],{"class":838},[824,3321,2769],{"class":838},[824,3323,958],{"class":834},[824,3325,3326,3328,3331,3333,3336,3338,3341],{"class":826,"line":868},[824,3327,831],{"class":830},[824,3329,3330],{"class":834}," url ",[824,3332,839],{"class":838},[824,3334,3335],{"class":834}," URL",[824,3337,782],{"class":838},[824,3339,3340],{"class":871},"createObjectURL",[824,3342,3343],{"class":834},"(blob)\n",[824,3345,3346,3348,3351,3353,3356,3358,3361,3363,3365,3367,3369],{"class":826,"line":908},[824,3347,831],{"class":830},[824,3349,3350],{"class":834}," a ",[824,3352,839],{"class":838},[824,3354,3355],{"class":834}," document",[824,3357,782],{"class":838},[824,3359,3360],{"class":871},"createElement",[824,3362,941],{"class":834},[824,3364,2178],{"class":838},[824,3366,772],{"class":1955},[824,3368,2178],{"class":838},[824,3370,958],{"class":834},[824,3372,3373,3375,3377,3380,3382],{"class":826,"line":920},[824,3374,772],{"class":834},[824,3376,782],{"class":838},[824,3378,3379],{"class":834},"href ",[824,3381,839],{"class":838},[824,3383,3384],{"class":834}," url\n",[824,3386,3387,3389,3391,3394,3396],{"class":826,"line":961},[824,3388,772],{"class":834},[824,3390,782],{"class":838},[824,3392,3393],{"class":834},"download ",[824,3395,839],{"class":838},[824,3397,3398],{"class":834}," filename\n",[824,3400,3401,3403,3405,3408],{"class":826,"line":975},[824,3402,772],{"class":834},[824,3404,782],{"class":838},[824,3406,3407],{"class":871},"click",[824,3409,1177],{"class":834},[824,3411,3412,3415,3417,3420],{"class":826,"line":982},[824,3413,3414],{"class":834},"URL",[824,3416,782],{"class":838},[824,3418,3419],{"class":871},"revokeObjectURL",[824,3421,3422],{"class":834},"(url)\n",[719,3424,3425,855],{},[1214,3426,3106],{},[1218,3428,3429,3432,3438],{},[1221,3430,3431],{},"Entire file loaded into memory",[1221,3433,3434,3435,899],{},"Hard limit 1.5GB (",[748,3436,3437],{},"MEMORY_CONFIG.maxBlobSize",[1221,3439,3440,3441,899],{},"Console warning when exceeding 800MB (",[748,3442,3443],{},"MEMORY_CONFIG.warnBlobSize",[752,3445,3447],{"id":3446},"strategy-comparison-summary","Strategy Comparison Summary",[1425,3449,3450,3465],{},[1428,3451,3452],{},[1431,3453,3454,3456,3459,3462],{},[1434,3455,1436],{},[1434,3457,3458],{},"FSA API",[1434,3460,3461],{},"StreamSaver.js",[1434,3463,3464],{},"Blob",[1444,3466,3467,3481,3494,3508,3521],{},[1431,3468,3469,3472,3475,3478],{},[1449,3470,3471],{},"Memory usage",[1449,3473,3474],{},"16MB (constant)",[1449,3476,3477],{},"Low (streaming)",[1449,3479,3480],{},"Equal to file size",[1431,3482,3483,3486,3489,3491],{},[1449,3484,3485],{},"File size limit",[1449,3487,3488],{},"Unlimited",[1449,3490,3488],{},[1449,3492,3493],{},"1.5GB",[1431,3495,3496,3499,3502,3505],{},[1449,3497,3498],{},"Browser requirement",[1449,3500,3501],{},"Chrome\u002FEdge 86+",[1449,3503,3504],{},"Service Worker support",[1449,3506,3507],{},"All browsers",[1431,3509,3510,3513,3516,3519],{},[1449,3511,3512],{},"Directory persistence",[1449,3514,3515],{},"Supported",[1449,3517,3518],{},"Not supported",[1449,3520,3518],{},[1431,3522,3523,3526,3529,3532],{},[1449,3524,3525],{},"Download experience",[1449,3527,3528],{},"Best",[1449,3530,3531],{},"Good",[1449,3533,3534],{},"Average",[1255,3536,3537],{},[719,3538,3539,3540,3544,3545,3549,3550,782],{},"For browser support status of these three strategies, see ",[772,3541,3543],{"href":3542},"\u002Fdocs\u002Fadvanced\u002Fbrowser-compatibility#feature-fallback-strategies","Browser Compatibility — Feature Fallback Strategies",". For write strategy usage in online tools, see ",[772,3546,3548],{"href":3547},"\u002Fdocs\u002Fadvanced\u002Fonline-tools#write-strategy-priority","Online Tools — Write Strategy Priority",". For Blob mode size limits and solutions, see ",[772,3551,3553],{"href":3552},"\u002Fdocs\u002Ftroubleshooting\u002Fknown-issues#file-size-limits","Known Limitations — File Size Limits",[733,3555,3557],{"id":3556},"memory-safety-management","Memory Safety Management",[719,3559,3560],{},[725,3561],{"alt":3562,"src":3563},"Memory Management Decision Flow","\u002Fscreenshots\u002Fmemory-management.png",[752,3565,3567],{"id":3566},"size-estimation","Size Estimation",[719,3569,3570],{},"Before starting download, engine samples to estimate total file size:",[741,3572,3574],{"className":818,"code":3573,"language":820,"meta":750,"style":750},"async function estimateSegmentsSize(\n  segments: ArrayBuffer[] | AsyncGenerator\u003CArrayBuffer>,\n  totalCount: number\n): Promise\u003C{ estimatedSize: number; isEstimate: boolean }> {\n  \u002F\u002F Sample count: min(5, max(1, totalCount * 0.1))\n  const sampleCount = Math.min(5, Math.max(1, Math.floor(totalCount * 0.1)))\n\n  \u002F\u002F Download first few segments and calculate average size\n  let sampledTotal = 0\n  for (let i = 0; i \u003C sampleCount; i++) {\n    sampledTotal += sampleSegment.byteLength\n  }\n\n  const avgSample = sampledTotal \u002F sampleCount\n  return {\n    estimatedSize: Math.round(avgSample * totalCount),\n    isEstimate: true\n  }\n}\n",[748,3575,3576,3587,3610,3619,3650,3655,3711,3715,3720,3731,3764,3778,3782,3786,3803,3809,3837,3847,3851],{"__ignoreMap":750},[824,3577,3578,3580,3582,3585],{"class":826,"line":827},[824,3579,1287],{"class":830},[824,3581,1290],{"class":830},[824,3583,3584],{"class":871}," estimateSegmentsSize",[824,3586,1130],{"class":838},[824,3588,3589,3591,3593,3595,3598,3601,3603,3605,3607],{"class":826,"line":848},[824,3590,852],{"class":851},[824,3592,855],{"class":838},[824,3594,885],{"class":858},[824,3596,3597],{"class":834},"[] ",[824,3599,3600],{"class":838},"|",[824,3602,1329],{"class":858},[824,3604,1332],{"class":838},[824,3606,1335],{"class":858},[824,3608,3609],{"class":838},">,\n",[824,3611,3612,3615,3617],{"class":826,"line":868},[824,3613,3614],{"class":851},"  totalCount",[824,3616,855],{"class":838},[824,3618,3158],{"class":858},[824,3620,3621,3623,3625,3628,3631,3633,3635,3637,3640,3642,3645,3648],{"class":826,"line":908},[824,3622,1326],{"class":838},[824,3624,1192],{"class":858},[824,3626,3627],{"class":838},"\u003C{",[824,3629,3630],{"class":940}," estimatedSize",[824,3632,855],{"class":838},[824,3634,896],{"class":858},[824,3636,1591],{"class":838},[824,3638,3639],{"class":940}," isEstimate",[824,3641,855],{"class":838},[824,3643,3644],{"class":858}," boolean",[824,3646,3647],{"class":838}," }>",[824,3649,917],{"class":838},[824,3651,3652],{"class":826,"line":920},[824,3653,3654],{"class":1688},"  \u002F\u002F Sample count: min(5, max(1, totalCount * 0.1))\n",[824,3656,3657,3659,3662,3664,3666,3668,3670,3672,3675,3677,3679,3681,3684,3686,3689,3691,3693,3695,3698,3700,3703,3705,3708],{"class":826,"line":961},[824,3658,923],{"class":830},[824,3660,3661],{"class":834}," sampleCount",[824,3663,929],{"class":838},[824,3665,932],{"class":834},[824,3667,782],{"class":838},[824,3669,937],{"class":871},[824,3671,941],{"class":940},[824,3673,3674],{"class":954},"5",[824,3676,888],{"class":838},[824,3678,932],{"class":834},[824,3680,782],{"class":838},[824,3682,3683],{"class":871},"max",[824,3685,941],{"class":940},[824,3687,3688],{"class":954},"1",[824,3690,888],{"class":838},[824,3692,932],{"class":834},[824,3694,782],{"class":838},[824,3696,3697],{"class":871},"floor",[824,3699,941],{"class":940},[824,3701,3702],{"class":834},"totalCount",[824,3704,3063],{"class":838},[824,3706,3707],{"class":954}," 0.1",[824,3709,3710],{"class":940},")))\n",[824,3712,3713],{"class":826,"line":975},[824,3714,979],{"emptyLinePlaceholder":978},[824,3716,3717],{"class":826,"line":982},[824,3718,3719],{"class":1688},"  \u002F\u002F Download first few segments and calculate average size\n",[824,3721,3722,3724,3727,3729],{"class":826,"line":1001},[824,3723,964],{"class":830},[824,3725,3726],{"class":834}," sampledTotal",[824,3728,929],{"class":838},[824,3730,972],{"class":954},[824,3732,3733,3735,3737,3739,3742,3744,3746,3748,3750,3752,3754,3756,3758,3760,3762],{"class":826,"line":1029},[824,3734,1345],{"class":1004},[824,3736,877],{"class":940},[824,3738,1580],{"class":830},[824,3740,3741],{"class":834}," i",[824,3743,929],{"class":838},[824,3745,1588],{"class":954},[824,3747,1591],{"class":838},[824,3749,3741],{"class":834},[824,3751,1013],{"class":838},[824,3753,3661],{"class":834},[824,3755,1591],{"class":838},[824,3757,3741],{"class":834},[824,3759,1605],{"class":838},[824,3761,911],{"class":940},[824,3763,1026],{"class":838},[824,3765,3766,3769,3771,3774,3776],{"class":826,"line":1044},[824,3767,3768],{"class":834},"    sampledTotal",[824,3770,2518],{"class":838},[824,3772,3773],{"class":834}," sampleSegment",[824,3775,782],{"class":838},[824,3777,2525],{"class":834},[824,3779,3780],{"class":826,"line":1079},[824,3781,1104],{"class":838},[824,3783,3784],{"class":826,"line":1095},[824,3785,979],{"emptyLinePlaceholder":978},[824,3787,3788,3790,3793,3795,3797,3800],{"class":826,"line":1101},[824,3789,923],{"class":830},[824,3791,3792],{"class":834}," avgSample",[824,3794,929],{"class":838},[824,3796,3726],{"class":834},[824,3798,3799],{"class":838}," \u002F",[824,3801,3802],{"class":834}," sampleCount\n",[824,3804,3805,3807],{"class":826,"line":1107},[824,3806,2351],{"class":1004},[824,3808,917],{"class":838},[824,3810,3811,3814,3816,3818,3820,3823,3825,3828,3830,3833,3835],{"class":826,"line":1112},[824,3812,3813],{"class":940},"    estimatedSize",[824,3815,855],{"class":838},[824,3817,932],{"class":834},[824,3819,782],{"class":838},[824,3821,3822],{"class":871},"round",[824,3824,941],{"class":940},[824,3826,3827],{"class":834},"avgSample",[824,3829,3063],{"class":838},[824,3831,3832],{"class":834}," totalCount",[824,3834,899],{"class":940},[824,3836,865],{"class":838},[824,3838,3839,3842,3844],{"class":826,"line":1133},[824,3840,3841],{"class":940},"    isEstimate",[824,3843,855],{"class":838},[824,3845,3846],{"class":2209}," true\n",[824,3848,3849],{"class":826,"line":1167},[824,3850,1104],{"class":838},[824,3852,3853],{"class":826,"line":1180},[824,3854,1210],{"class":838},[719,3856,3857,855],{},[1214,3858,3859],{},"Sampling Strategy Explanation",[1218,3861,3862,3869,3876],{},[1221,3863,3864,3865,3868],{},"Sample count takes ",[748,3866,3867],{},"min(5, max(1, total segments × 10%))",", ensuring small streams sample at least 1, large streams at most 5",[1221,3870,3871,3872,3875],{},"Sampling result marked ",[748,3873,3874],{},"isEstimate: true",", UI layer displays \"~XX MB\" instead of exact value based on this",[1221,3877,3878,3879,3882],{},"For HLS streams, if Master Playlist declares ",[748,3880,3881],{},"BANDWIDTH"," attribute, engine prioritizes using that value as estimation reference",[752,3884,3886],{"id":3885},"strategy-selection-logic","Strategy Selection Logic",[741,3888,3891],{"className":3889,"code":3890,"language":746},[744],"Estimated size \u003C 800MB  → Any strategy acceptable\nEstimated size 800MB-1.5GB → Prioritize streaming write, Blob mode shows warning\nEstimated size > 1.5GB → Force streaming write, Blob mode refused\n",[748,3892,3890],{"__ignoreMap":750},[752,3894,3896],{"id":3895},"memory-configuration-constants","Memory Configuration Constants",[741,3898,3900],{"className":818,"code":3899,"language":820,"meta":750,"style":750},"const MEMORY_CONFIG = {\n  maxBlobSize: 1500 * 1024 * 1024,    \u002F\u002F 1.5GB hard limit\n  warnBlobSize: 800 * 1024 * 1024,    \u002F\u002F 800MB warning threshold\n}\n",[748,3901,3902,3913,3936,3959],{"__ignoreMap":750},[824,3903,3904,3906,3909,3911],{"class":826,"line":827},[824,3905,831],{"class":830},[824,3907,3908],{"class":834}," MEMORY_CONFIG ",[824,3910,839],{"class":838},[824,3912,917],{"class":838},[824,3914,3915,3918,3920,3923,3925,3927,3929,3931,3933],{"class":826,"line":848},[824,3916,3917],{"class":940},"  maxBlobSize",[824,3919,855],{"class":838},[824,3921,3922],{"class":954}," 1500",[824,3924,3063],{"class":838},[824,3926,3066],{"class":954},[824,3928,3063],{"class":838},[824,3930,3066],{"class":954},[824,3932,888],{"class":838},[824,3934,3935],{"class":1688},"    \u002F\u002F 1.5GB hard limit\n",[824,3937,3938,3941,3943,3946,3948,3950,3952,3954,3956],{"class":826,"line":868},[824,3939,3940],{"class":940},"  warnBlobSize",[824,3942,855],{"class":838},[824,3944,3945],{"class":954}," 800",[824,3947,3063],{"class":838},[824,3949,3066],{"class":954},[824,3951,3063],{"class":838},[824,3953,3066],{"class":954},[824,3955,888],{"class":838},[824,3957,3958],{"class":1688},"    \u002F\u002F 800MB warning threshold\n",[824,3960,3961],{"class":826,"line":908},[824,3962,1210],{"class":838},[752,3964,3966],{"id":3965},"runtime-memory-monitoring","Runtime Memory Monitoring",[719,3968,3969],{},"In addition to pre-download estimation, engine continuously monitors memory pressure during runtime:",[741,3971,3973],{"className":818,"code":3972,"language":820,"meta":750,"style":750},"const checkMemoryPressure = (): 'normal' | 'warning' | 'critical' => {\n  \u002F\u002F Check current total allocated segment buffer size\n  const allocatedMB = allocatedBuffers.reduce((sum, buf) => sum + buf.byteLength, 0) \u002F 1048576\n\n  if (allocatedMB > 1200) return 'critical'\n  if (allocatedMB > 600) return 'warning'\n  return 'normal'\n}\n",[748,3974,3975,4016,4021,4079,4083,4109,4132,4142],{"__ignoreMap":750},[824,3976,3977,3979,3982,3984,3987,3989,3992,3994,3996,3998,4001,4003,4005,4007,4010,4012,4014],{"class":826,"line":827},[824,3978,831],{"class":830},[824,3980,3981],{"class":834}," checkMemoryPressure ",[824,3983,839],{"class":838},[824,3985,3986],{"class":838}," ():",[824,3988,1952],{"class":838},[824,3990,3991],{"class":1955},"normal",[824,3993,2178],{"class":838},[824,3995,2672],{"class":838},[824,3997,1952],{"class":838},[824,3999,4000],{"class":1955},"warning",[824,4002,2178],{"class":838},[824,4004,2672],{"class":838},[824,4006,1952],{"class":838},[824,4008,4009],{"class":1955},"critical",[824,4011,2178],{"class":838},[824,4013,902],{"class":830},[824,4015,917],{"class":838},[824,4017,4018],{"class":826,"line":848},[824,4019,4020],{"class":1688},"  \u002F\u002F Check current total allocated segment buffer size\n",[824,4022,4023,4025,4028,4030,4033,4035,4038,4040,4042,4045,4047,4050,4052,4054,4057,4060,4062,4064,4067,4069,4071,4073,4076],{"class":826,"line":868},[824,4024,923],{"class":830},[824,4026,4027],{"class":834}," allocatedMB",[824,4029,929],{"class":838},[824,4031,4032],{"class":834}," allocatedBuffers",[824,4034,782],{"class":838},[824,4036,4037],{"class":871},"reduce",[824,4039,941],{"class":940},[824,4041,941],{"class":838},[824,4043,4044],{"class":851},"sum",[824,4046,888],{"class":838},[824,4048,4049],{"class":851}," buf",[824,4051,899],{"class":838},[824,4053,902],{"class":830},[824,4055,4056],{"class":834}," sum",[824,4058,4059],{"class":838}," +",[824,4061,4049],{"class":834},[824,4063,782],{"class":838},[824,4065,4066],{"class":834},"byteLength",[824,4068,888],{"class":838},[824,4070,1588],{"class":954},[824,4072,911],{"class":940},[824,4074,4075],{"class":838},"\u002F",[824,4077,4078],{"class":954}," 1048576\n",[824,4080,4081],{"class":826,"line":908},[824,4082,979],{"emptyLinePlaceholder":978},[824,4084,4085,4087,4089,4092,4095,4098,4100,4103,4105,4107],{"class":826,"line":920},[824,4086,2717],{"class":1004},[824,4088,877],{"class":940},[824,4090,4091],{"class":834},"allocatedMB",[824,4093,4094],{"class":838}," >",[824,4096,4097],{"class":954}," 1200",[824,4099,911],{"class":940},[824,4101,4102],{"class":1004},"return",[824,4104,1952],{"class":838},[824,4106,4009],{"class":1955},[824,4108,1959],{"class":838},[824,4110,4111,4113,4115,4117,4119,4122,4124,4126,4128,4130],{"class":826,"line":961},[824,4112,2717],{"class":1004},[824,4114,877],{"class":940},[824,4116,4091],{"class":834},[824,4118,4094],{"class":838},[824,4120,4121],{"class":954}," 600",[824,4123,911],{"class":940},[824,4125,4102],{"class":1004},[824,4127,1952],{"class":838},[824,4129,4000],{"class":1955},[824,4131,1959],{"class":838},[824,4133,4134,4136,4138,4140],{"class":826,"line":975},[824,4135,2351],{"class":1004},[824,4137,1952],{"class":838},[824,4139,3991],{"class":1955},[824,4141,1959],{"class":838},[824,4143,4144],{"class":826,"line":982},[824,4145,1210],{"class":838},[719,4147,4148,4149,4151],{},"When memory pressure reaches ",[748,4150,4009],{}," level, engine will:",[1218,4153,4154,4157,4160],{},[1221,4155,4156],{},"Pause new segment download requests",[1221,4158,4159],{},"Prioritize writing already downloaded segments to disk",[1221,4161,4162],{},"Release buffers for segments already written",[766,4164,4165],{},[719,4166,4167,4168,4170,4171,782],{},"Memory safety is one of core design considerations for FlowPick's download engine. For very large files (e.g., 20GB+ live replays), engine forces streaming write strategy to ensure browser doesn't crash due to insufficient memory. For actual scenarios of large file downloads, see ",[772,4169,1495],{"href":112},". For troubleshooting large file download failures, see ",[772,4172,4174],{"href":4173},"\u002Fdocs\u002Ftroubleshooting\u002Fcommon-issues#large-file-download-failure","Common Issues Troubleshooting — Large File Download Failure",[733,4176,4178],{"id":4177},"progress-tracking","Progress Tracking",[752,4180,4182],{"id":4181},"speed-calculation","Speed Calculation",[719,4184,4185],{},"Engine uses sliding window algorithm to calculate real-time download speed:",[741,4187,4189],{"className":818,"code":4188,"language":820,"meta":750,"style":750},"class SpeedCalculator {\n  private samples: Array\u003C{ bytes: number; timestamp: number }> = []\n  private readonly WINDOW_SIZE = 5000 \u002F\u002F 5 second window\n\n  record(bytesDownloaded: number): void {\n    this.samples.push({ bytes: bytesDownloaded, timestamp: Date.now() })\n    \u002F\u002F Remove samples older than window\n    const cutoff = Date.now() - this.WINDOW_SIZE\n    this.samples = this.samples.filter(s => s.timestamp >= cutoff)\n  }\n\n  getSpeed(): number {\n    if (this.samples.length \u003C 2) return 0\n    \n    const oldest = this.samples[0]!\n    const newest = this.samples[this.samples.length - 1]!\n    \n    const timeDiff = (newest.timestamp - oldest.timestamp) \u002F 1000 \u002F\u002F seconds\n    const byteDiff = newest.bytes - oldest.bytes\n    \n    return timeDiff > 0 ? byteDiff \u002F timeDiff : 0\n  }\n}\n",[748,4190,4191,4200,4237,4255,4259,4280,4325,4330,4356,4395,4399,4403,4415,4441,4446,4469,4500,4504,4540,4565,4569,4593,4597],{"__ignoreMap":750},[824,4192,4193,4195,4198],{"class":826,"line":827},[824,4194,1864],{"class":830},[824,4196,4197],{"class":858}," SpeedCalculator",[824,4199,917],{"class":838},[824,4201,4202,4205,4208,4210,4212,4214,4217,4219,4221,4223,4226,4228,4230,4232,4234],{"class":826,"line":848},[824,4203,4204],{"class":830},"  private",[824,4206,4207],{"class":940}," samples",[824,4209,855],{"class":838},[824,4211,1122],{"class":858},[824,4213,3627],{"class":838},[824,4215,4216],{"class":940}," bytes",[824,4218,855],{"class":838},[824,4220,896],{"class":858},[824,4222,1591],{"class":838},[824,4224,4225],{"class":940}," timestamp",[824,4227,855],{"class":838},[824,4229,896],{"class":858},[824,4231,3647],{"class":838},[824,4233,929],{"class":838},[824,4235,4236],{"class":834}," []\n",[824,4238,4239,4241,4244,4247,4249,4252],{"class":826,"line":868},[824,4240,4204],{"class":830},[824,4242,4243],{"class":830}," readonly",[824,4245,4246],{"class":940}," WINDOW_SIZE",[824,4248,929],{"class":838},[824,4250,4251],{"class":954}," 5000",[824,4253,4254],{"class":1688}," \u002F\u002F 5 second window\n",[824,4256,4257],{"class":826,"line":908},[824,4258,979],{"emptyLinePlaceholder":978},[824,4260,4261,4264,4266,4269,4271,4273,4275,4278],{"class":826,"line":920},[824,4262,4263],{"class":940},"  record",[824,4265,941],{"class":838},[824,4267,4268],{"class":851},"bytesDownloaded",[824,4270,855],{"class":838},[824,4272,896],{"class":858},[824,4274,1326],{"class":838},[824,4276,4277],{"class":858}," void",[824,4279,917],{"class":838},[824,4281,4282,4284,4287,4289,4292,4294,4297,4299,4301,4304,4306,4308,4310,4313,4315,4318,4320,4323],{"class":826,"line":961},[824,4283,1944],{"class":838},[824,4285,4286],{"class":834},"samples",[824,4288,782],{"class":838},[824,4290,4291],{"class":871},"push",[824,4293,941],{"class":940},[824,4295,4296],{"class":838},"{",[824,4298,4216],{"class":940},[824,4300,855],{"class":838},[824,4302,4303],{"class":834}," bytesDownloaded",[824,4305,888],{"class":838},[824,4307,4225],{"class":940},[824,4309,855],{"class":838},[824,4311,4312],{"class":834}," Date",[824,4314,782],{"class":838},[824,4316,4317],{"class":871},"now",[824,4319,3005],{"class":940},[824,4321,4322],{"class":838},"}",[824,4324,958],{"class":940},[824,4326,4327],{"class":826,"line":975},[824,4328,4329],{"class":1688},"    \u002F\u002F Remove samples older than window\n",[824,4331,4332,4334,4337,4339,4341,4343,4345,4347,4350,4353],{"class":826,"line":982},[824,4333,1387],{"class":830},[824,4335,4336],{"class":834}," cutoff",[824,4338,929],{"class":838},[824,4340,4312],{"class":834},[824,4342,782],{"class":838},[824,4344,4317],{"class":871},[824,4346,3005],{"class":940},[824,4348,4349],{"class":838},"-",[824,4351,4352],{"class":838}," this.",[824,4354,4355],{"class":834},"WINDOW_SIZE\n",[824,4357,4358,4360,4362,4364,4366,4368,4370,4373,4375,4378,4380,4383,4385,4388,4391,4393],{"class":826,"line":1001},[824,4359,1944],{"class":838},[824,4361,4286],{"class":834},[824,4363,929],{"class":838},[824,4365,4352],{"class":838},[824,4367,4286],{"class":834},[824,4369,782],{"class":838},[824,4371,4372],{"class":871},"filter",[824,4374,941],{"class":940},[824,4376,4377],{"class":851},"s",[824,4379,902],{"class":830},[824,4381,4382],{"class":834}," s",[824,4384,782],{"class":838},[824,4386,4387],{"class":834},"timestamp",[824,4389,4390],{"class":838}," >=",[824,4392,4336],{"class":834},[824,4394,958],{"class":940},[824,4396,4397],{"class":826,"line":1029},[824,4398,1104],{"class":838},[824,4400,4401],{"class":826,"line":1044},[824,4402,979],{"emptyLinePlaceholder":978},[824,4404,4405,4408,4411,4413],{"class":826,"line":1079},[824,4406,4407],{"class":940},"  getSpeed",[824,4409,4410],{"class":838},"():",[824,4412,896],{"class":858},[824,4414,917],{"class":838},[824,4416,4417,4419,4421,4424,4426,4428,4430,4432,4435,4437,4439],{"class":826,"line":1095},[824,4418,1366],{"class":1004},[824,4420,877],{"class":940},[824,4422,4423],{"class":838},"this.",[824,4425,4286],{"class":834},[824,4427,782],{"class":838},[824,4429,1021],{"class":834},[824,4431,1013],{"class":838},[824,4433,4434],{"class":954}," 2",[824,4436,911],{"class":940},[824,4438,4102],{"class":1004},[824,4440,972],{"class":954},[824,4442,4443],{"class":826,"line":1101},[824,4444,4445],{"class":940},"    \n",[824,4447,4448,4450,4453,4455,4457,4459,4461,4464,4466],{"class":826,"line":1107},[824,4449,1387],{"class":830},[824,4451,4452],{"class":834}," oldest",[824,4454,929],{"class":838},[824,4456,4352],{"class":838},[824,4458,4286],{"class":834},[824,4460,1065],{"class":940},[824,4462,4463],{"class":954},"0",[824,4465,1071],{"class":940},[824,4467,4468],{"class":838},"!\n",[824,4470,4471,4473,4476,4478,4480,4482,4484,4486,4488,4490,4492,4494,4496,4498],{"class":826,"line":1112},[824,4472,1387],{"class":830},[824,4474,4475],{"class":834}," newest",[824,4477,929],{"class":838},[824,4479,4352],{"class":838},[824,4481,4286],{"class":834},[824,4483,1065],{"class":940},[824,4485,4423],{"class":838},[824,4487,4286],{"class":834},[824,4489,782],{"class":838},[824,4491,1021],{"class":834},[824,4493,1676],{"class":838},[824,4495,1679],{"class":954},[824,4497,1071],{"class":940},[824,4499,4468],{"class":838},[824,4501,4502],{"class":826,"line":1133},[824,4503,4445],{"class":940},[824,4505,4506,4508,4511,4513,4515,4518,4520,4522,4524,4526,4528,4530,4532,4534,4537],{"class":826,"line":1167},[824,4507,1387],{"class":830},[824,4509,4510],{"class":834}," timeDiff",[824,4512,929],{"class":838},[824,4514,877],{"class":940},[824,4516,4517],{"class":834},"newest",[824,4519,782],{"class":838},[824,4521,4387],{"class":834},[824,4523,1676],{"class":838},[824,4525,4452],{"class":834},[824,4527,782],{"class":838},[824,4529,4387],{"class":834},[824,4531,911],{"class":940},[824,4533,4075],{"class":838},[824,4535,4536],{"class":954}," 1000",[824,4538,4539],{"class":1688}," \u002F\u002F seconds\n",[824,4541,4542,4544,4547,4549,4551,4553,4556,4558,4560,4562],{"class":826,"line":1180},[824,4543,1387],{"class":830},[824,4545,4546],{"class":834}," byteDiff",[824,4548,929],{"class":838},[824,4550,4475],{"class":834},[824,4552,782],{"class":838},[824,4554,4555],{"class":834},"bytes",[824,4557,1676],{"class":838},[824,4559,4452],{"class":834},[824,4561,782],{"class":838},[824,4563,4564],{"class":834},"bytes\n",[824,4566,4567],{"class":826,"line":1186},[824,4568,4445],{"class":940},[824,4570,4571,4574,4576,4578,4580,4582,4584,4586,4588,4591],{"class":826,"line":1207},[824,4572,4573],{"class":1004},"    return",[824,4575,4510],{"class":834},[824,4577,4094],{"class":838},[824,4579,1588],{"class":954},[824,4581,2250],{"class":838},[824,4583,4546],{"class":834},[824,4585,3799],{"class":838},[824,4587,4510],{"class":834},[824,4589,4590],{"class":838}," :",[824,4592,972],{"class":954},[824,4594,4595],{"class":826,"line":2357},[824,4596,1104],{"class":838},[824,4598,4599],{"class":826,"line":2928},[824,4600,1210],{"class":838},[719,4602,4603,855],{},[1214,4604,4605],{},"Algorithm Characteristics",[1218,4607,4608,4614,4620],{},[1221,4609,4610,4613],{},[1214,4611,4612],{},"Sliding window",": Only considers data from recent 5 seconds, avoids historical data interference",[1221,4615,4616,4619],{},[1214,4617,4618],{},"Responsive",": Speed update reflects current network conditions in near real-time",[1221,4621,4622,4625],{},[1214,4623,4624],{},"Smooth",": Averages out momentary fluctuations, providing stable display value",[719,4627,4628,855],{},[1214,4629,4630],{},"Display Format",[1425,4632,4633,4646],{},[1428,4634,4635],{},[1431,4636,4637,4640,4643],{},[1434,4638,4639],{},"Speed Range",[1434,4641,4642],{},"Display Unit",[1434,4644,4645],{},"Example",[1444,4647,4648,4659,4670],{},[1431,4649,4650,4653,4656],{},[1449,4651,4652],{},"\u003C 1 MB\u002Fs",[1449,4654,4655],{},"KB\u002Fs",[1449,4657,4658],{},"512 KB\u002Fs",[1431,4660,4661,4664,4667],{},[1449,4662,4663],{},"1-1024 MB\u002Fs",[1449,4665,4666],{},"MB\u002Fs",[1449,4668,4669],{},"5.2 MB\u002Fs",[1431,4671,4672,4675,4678],{},[1449,4673,4674],{},"> 1024 MB\u002Fs",[1449,4676,4677],{},"GB\u002Fs",[1449,4679,4680],{},"1.3 GB\u002Fs",[752,4682,4684],{"id":4683},"eta-calculation","ETA Calculation",[719,4686,4687],{},"Estimated Time of Arrival (ETA) calculated based on current speed and remaining work:",[741,4689,4691],{"className":818,"code":4690,"language":820,"meta":750,"style":750},"function calculateETA(\n  downloadedBytes: number,\n  totalBytes: number,\n  currentSpeed: number\n): string {\n  if (currentSpeed \u003C= 0 || downloadedBytes >= totalBytes) return '--'\n  \n  const remainingBytes = totalBytes - downloadedBytes\n  const remainingSeconds = remainingBytes \u002F currentSpeed\n  \n  return formatDuration(remainingSeconds)\n}\n\nfunction formatDuration(seconds: number): string {\n  if (seconds \u003C 60) return `${Math.round(seconds)}s`\n  if (seconds \u003C 3600) return `${Math.floor(seconds \u002F 60)}m ${Math.round(seconds % 60)}s`\n  return `${Math.floor(seconds \u002F 3600)}h ${Math.floor((seconds % 3600) \u002F 60)}m`\n}\n",[748,4692,4693,4703,4714,4725,4734,4742,4778,4783,4799,4815,4819,4833,4837,4841,4862,4899,4962,5017],{"__ignoreMap":750},[824,4694,4695,4698,4701],{"class":826,"line":827},[824,4696,4697],{"class":830},"function",[824,4699,4700],{"class":871}," calculateETA",[824,4702,1130],{"class":838},[824,4704,4705,4708,4710,4712],{"class":826,"line":848},[824,4706,4707],{"class":851},"  downloadedBytes",[824,4709,855],{"class":838},[824,4711,896],{"class":858},[824,4713,865],{"class":838},[824,4715,4716,4719,4721,4723],{"class":826,"line":868},[824,4717,4718],{"class":851},"  totalBytes",[824,4720,855],{"class":838},[824,4722,896],{"class":858},[824,4724,865],{"class":838},[824,4726,4727,4730,4732],{"class":826,"line":908},[824,4728,4729],{"class":851},"  currentSpeed",[824,4731,855],{"class":838},[824,4733,3158],{"class":858},[824,4735,4736,4738,4740],{"class":826,"line":920},[824,4737,1326],{"class":838},[824,4739,1892],{"class":858},[824,4741,917],{"class":838},[824,4743,4744,4746,4748,4751,4754,4756,4759,4762,4764,4767,4769,4771,4773,4776],{"class":826,"line":961},[824,4745,2717],{"class":1004},[824,4747,877],{"class":940},[824,4749,4750],{"class":834},"currentSpeed",[824,4752,4753],{"class":838}," \u003C=",[824,4755,1588],{"class":954},[824,4757,4758],{"class":838}," ||",[824,4760,4761],{"class":834}," downloadedBytes",[824,4763,4390],{"class":838},[824,4765,4766],{"class":834}," totalBytes",[824,4768,911],{"class":940},[824,4770,4102],{"class":1004},[824,4772,1952],{"class":838},[824,4774,4775],{"class":1955},"--",[824,4777,1959],{"class":838},[824,4779,4780],{"class":826,"line":975},[824,4781,4782],{"class":940},"  \n",[824,4784,4785,4787,4790,4792,4794,4796],{"class":826,"line":982},[824,4786,923],{"class":830},[824,4788,4789],{"class":834}," remainingBytes",[824,4791,929],{"class":838},[824,4793,4766],{"class":834},[824,4795,1676],{"class":838},[824,4797,4798],{"class":834}," downloadedBytes\n",[824,4800,4801,4803,4806,4808,4810,4812],{"class":826,"line":1001},[824,4802,923],{"class":830},[824,4804,4805],{"class":834}," remainingSeconds",[824,4807,929],{"class":838},[824,4809,4789],{"class":834},[824,4811,3799],{"class":838},[824,4813,4814],{"class":834}," currentSpeed\n",[824,4816,4817],{"class":826,"line":1029},[824,4818,4782],{"class":940},[824,4820,4821,4823,4826,4828,4831],{"class":826,"line":1044},[824,4822,2351],{"class":1004},[824,4824,4825],{"class":871}," formatDuration",[824,4827,941],{"class":940},[824,4829,4830],{"class":834},"remainingSeconds",[824,4832,958],{"class":940},[824,4834,4835],{"class":826,"line":1079},[824,4836,1210],{"class":838},[824,4838,4839],{"class":826,"line":1095},[824,4840,979],{"emptyLinePlaceholder":978},[824,4842,4843,4845,4847,4849,4852,4854,4856,4858,4860],{"class":826,"line":1101},[824,4844,4697],{"class":830},[824,4846,4825],{"class":871},[824,4848,941],{"class":838},[824,4850,4851],{"class":851},"seconds",[824,4853,855],{"class":838},[824,4855,896],{"class":858},[824,4857,1326],{"class":838},[824,4859,1892],{"class":858},[824,4861,917],{"class":838},[824,4863,4864,4866,4868,4870,4872,4875,4877,4879,4882,4885,4887,4889,4892,4894,4896],{"class":826,"line":1107},[824,4865,2717],{"class":1004},[824,4867,877],{"class":940},[824,4869,4851],{"class":834},[824,4871,1013],{"class":838},[824,4873,4874],{"class":954}," 60",[824,4876,911],{"class":940},[824,4878,4102],{"class":1004},[824,4880,4881],{"class":838}," `${",[824,4883,4884],{"class":834},"Math",[824,4886,782],{"class":838},[824,4888,3822],{"class":871},[824,4890,4891],{"class":834},"(seconds)",[824,4893,4322],{"class":838},[824,4895,4377],{"class":1955},[824,4897,4898],{"class":838},"`\n",[824,4900,4901,4903,4905,4907,4909,4912,4914,4916,4918,4920,4922,4924,4927,4929,4931,4933,4935,4938,4941,4943,4945,4947,4949,4952,4954,4956,4958,4960],{"class":826,"line":1112},[824,4902,2717],{"class":1004},[824,4904,877],{"class":940},[824,4906,4851],{"class":834},[824,4908,1013],{"class":838},[824,4910,4911],{"class":954}," 3600",[824,4913,911],{"class":940},[824,4915,4102],{"class":1004},[824,4917,4881],{"class":838},[824,4919,4884],{"class":834},[824,4921,782],{"class":838},[824,4923,3697],{"class":871},[824,4925,4926],{"class":834},"(seconds ",[824,4928,4075],{"class":838},[824,4930,4874],{"class":954},[824,4932,899],{"class":834},[824,4934,4322],{"class":838},[824,4936,4937],{"class":1955},"m ",[824,4939,4940],{"class":838},"${",[824,4942,4884],{"class":834},[824,4944,782],{"class":838},[824,4946,3822],{"class":871},[824,4948,4926],{"class":834},[824,4950,4951],{"class":838},"%",[824,4953,4874],{"class":954},[824,4955,899],{"class":834},[824,4957,4322],{"class":838},[824,4959,4377],{"class":1955},[824,4961,4898],{"class":838},[824,4963,4964,4966,4968,4970,4972,4974,4976,4978,4980,4982,4984,4987,4989,4991,4993,4995,4998,5000,5002,5004,5006,5008,5010,5012,5015],{"class":826,"line":1133},[824,4965,2351],{"class":1004},[824,4967,4881],{"class":838},[824,4969,4884],{"class":834},[824,4971,782],{"class":838},[824,4973,3697],{"class":871},[824,4975,4926],{"class":834},[824,4977,4075],{"class":838},[824,4979,4911],{"class":954},[824,4981,899],{"class":834},[824,4983,4322],{"class":838},[824,4985,4986],{"class":1955},"h ",[824,4988,4940],{"class":838},[824,4990,4884],{"class":834},[824,4992,782],{"class":838},[824,4994,3697],{"class":871},[824,4996,4997],{"class":834},"((seconds ",[824,4999,4951],{"class":838},[824,5001,4911],{"class":954},[824,5003,911],{"class":834},[824,5005,4075],{"class":838},[824,5007,4874],{"class":954},[824,5009,899],{"class":834},[824,5011,4322],{"class":838},[824,5013,5014],{"class":1955},"m",[824,5016,4898],{"class":838},[824,5018,5019],{"class":826,"line":1167},[824,5020,1210],{"class":838},[719,5022,5023,855],{},[1214,5024,5025],{},"Calculation Logic",[1218,5027,5028,5035,5038],{},[1221,5029,5030,5031,5034],{},"Based on ",[1214,5032,5033],{},"sliding window average speed",", not instantaneous speed",[1221,5036,5037],{},"Dynamically adjusts to network condition changes",[1221,5039,5040],{},"Shows \"--\" when speed is zero or download complete",[752,5042,5044],{"id":5043},"progress-event-structure","Progress Event Structure",[719,5046,5047],{},"Engine emits structured progress events for UI layer consumption:",[741,5049,5051],{"className":818,"code":5050,"language":820,"meta":750,"style":750},"interface DownloadProgress {\n  \u002F\u002F Basic info\n  stage: 'parsing' | 'downloading' | 'processing' | 'writing' | 'completed'\n  \n  \u002F\u002F Overall progress\n  percent: number                    \u002F\u002F 0-100\n  downloadedBytes: number            \u002F\u002F Total downloaded bytes\n  totalBytes: number                \u002F\u002F Estimated or exact total\n  \n  \u002F\u002F Speed info\n  speed: number                     \u002F\u002F Bytes per second\n  eta: number                       \u002F\u002F Estimated remaining seconds\n  \n  \u002F\u002F Segment-level detail\n  completedSegments: number         \u002F\u002F Completed segment count\n  totalSegments: number             \u002F\u002F Total segment count\n  \n  \u002F\u002F Error info (if any)\n  error?: {\n    type: string\n    message: string\n    segmentIndex?: number\n    recoverable: boolean\n  }\n}\n",[748,5052,5053,5063,5068,5118,5122,5127,5139,5150,5161,5165,5170,5182,5194,5198,5203,5215,5227,5231,5236,5245,5254,5262,5271,5281,5285],{"__ignoreMap":750},[824,5054,5055,5058,5061],{"class":826,"line":827},[824,5056,5057],{"class":830},"interface",[824,5059,5060],{"class":858}," DownloadProgress",[824,5062,917],{"class":838},[824,5064,5065],{"class":826,"line":848},[824,5066,5067],{"class":1688},"  \u002F\u002F Basic info\n",[824,5069,5070,5073,5075,5077,5080,5082,5084,5086,5089,5091,5093,5095,5098,5100,5102,5104,5107,5109,5111,5113,5116],{"class":826,"line":868},[824,5071,5072],{"class":940},"  stage",[824,5074,855],{"class":838},[824,5076,1952],{"class":838},[824,5078,5079],{"class":1955},"parsing",[824,5081,2178],{"class":838},[824,5083,2672],{"class":838},[824,5085,1952],{"class":838},[824,5087,5088],{"class":1955},"downloading",[824,5090,2178],{"class":838},[824,5092,2672],{"class":838},[824,5094,1952],{"class":838},[824,5096,5097],{"class":1955},"processing",[824,5099,2178],{"class":838},[824,5101,2672],{"class":838},[824,5103,1952],{"class":838},[824,5105,5106],{"class":1955},"writing",[824,5108,2178],{"class":838},[824,5110,2672],{"class":838},[824,5112,1952],{"class":838},[824,5114,5115],{"class":1955},"completed",[824,5117,1959],{"class":838},[824,5119,5120],{"class":826,"line":908},[824,5121,4782],{"class":834},[824,5123,5124],{"class":826,"line":920},[824,5125,5126],{"class":1688},"  \u002F\u002F Overall progress\n",[824,5128,5129,5132,5134,5136],{"class":826,"line":961},[824,5130,5131],{"class":940},"  percent",[824,5133,855],{"class":838},[824,5135,896],{"class":858},[824,5137,5138],{"class":1688},"                    \u002F\u002F 0-100\n",[824,5140,5141,5143,5145,5147],{"class":826,"line":975},[824,5142,4707],{"class":940},[824,5144,855],{"class":838},[824,5146,896],{"class":858},[824,5148,5149],{"class":1688},"            \u002F\u002F Total downloaded bytes\n",[824,5151,5152,5154,5156,5158],{"class":826,"line":982},[824,5153,4718],{"class":940},[824,5155,855],{"class":838},[824,5157,896],{"class":858},[824,5159,5160],{"class":1688},"                \u002F\u002F Estimated or exact total\n",[824,5162,5163],{"class":826,"line":1001},[824,5164,4782],{"class":834},[824,5166,5167],{"class":826,"line":1029},[824,5168,5169],{"class":1688},"  \u002F\u002F Speed info\n",[824,5171,5172,5175,5177,5179],{"class":826,"line":1044},[824,5173,5174],{"class":940},"  speed",[824,5176,855],{"class":838},[824,5178,896],{"class":858},[824,5180,5181],{"class":1688},"                     \u002F\u002F Bytes per second\n",[824,5183,5184,5187,5189,5191],{"class":826,"line":1079},[824,5185,5186],{"class":940},"  eta",[824,5188,855],{"class":838},[824,5190,896],{"class":858},[824,5192,5193],{"class":1688},"                       \u002F\u002F Estimated remaining seconds\n",[824,5195,5196],{"class":826,"line":1095},[824,5197,4782],{"class":834},[824,5199,5200],{"class":826,"line":1101},[824,5201,5202],{"class":1688},"  \u002F\u002F Segment-level detail\n",[824,5204,5205,5208,5210,5212],{"class":826,"line":1107},[824,5206,5207],{"class":940},"  completedSegments",[824,5209,855],{"class":838},[824,5211,896],{"class":858},[824,5213,5214],{"class":1688},"         \u002F\u002F Completed segment count\n",[824,5216,5217,5220,5222,5224],{"class":826,"line":1112},[824,5218,5219],{"class":940},"  totalSegments",[824,5221,855],{"class":838},[824,5223,896],{"class":858},[824,5225,5226],{"class":1688},"             \u002F\u002F Total segment count\n",[824,5228,5229],{"class":826,"line":1133},[824,5230,4782],{"class":834},[824,5232,5233],{"class":826,"line":1167},[824,5234,5235],{"class":1688},"  \u002F\u002F Error info (if any)\n",[824,5237,5238,5241,5243],{"class":826,"line":1180},[824,5239,5240],{"class":940},"  error",[824,5242,1318],{"class":838},[824,5244,917],{"class":838},[824,5246,5247,5250,5252],{"class":826,"line":1186},[824,5248,5249],{"class":940},"    type",[824,5251,855],{"class":838},[824,5253,1920],{"class":858},[824,5255,5256,5258,5260],{"class":826,"line":1207},[824,5257,1887],{"class":940},[824,5259,855],{"class":838},[824,5261,1920],{"class":858},[824,5263,5264,5267,5269],{"class":826,"line":2357},[824,5265,5266],{"class":940},"    segmentIndex",[824,5268,1318],{"class":838},[824,5270,3158],{"class":858},[824,5272,5273,5276,5278],{"class":826,"line":2928},[824,5274,5275],{"class":940},"    recoverable",[824,5277,855],{"class":838},[824,5279,5280],{"class":858}," boolean\n",[824,5282,5283],{"class":826,"line":2948},[824,5284,1104],{"class":838},[824,5286,5287],{"class":826,"line":2983},[824,5288,1210],{"class":838},[719,5290,5291,855],{},[1214,5292,5293],{},"Event Throttling",[719,5295,5296],{},"To avoid excessive UI updates, progress events throttled to maximum 10 times per second:",[741,5298,5300],{"className":818,"code":5299,"language":820,"meta":750,"style":750},"const THROTTLE_INTERVAL = 100 \u002F\u002F 100ms minimum interval\n\nlet lastEmitTime = 0\nfunction emitProgress(progress: DownloadProgress) {\n  const now = Date.now()\n  if (now - lastEmitTime \u003C THROTTLE_INTERVAL) return\n  \n  lastEmitTime = now\n  eventEmitter.emit('progress', progress)\n}\n",[748,5301,5302,5317,5321,5332,5352,5369,5392,5396,5406,5431],{"__ignoreMap":750},[824,5303,5304,5306,5309,5311,5314],{"class":826,"line":827},[824,5305,831],{"class":830},[824,5307,5308],{"class":834}," THROTTLE_INTERVAL ",[824,5310,839],{"class":838},[824,5312,5313],{"class":954}," 100",[824,5315,5316],{"class":1688}," \u002F\u002F 100ms minimum interval\n",[824,5318,5319],{"class":826,"line":848},[824,5320,979],{"emptyLinePlaceholder":978},[824,5322,5323,5325,5328,5330],{"class":826,"line":868},[824,5324,1580],{"class":830},[824,5326,5327],{"class":834}," lastEmitTime ",[824,5329,839],{"class":838},[824,5331,972],{"class":954},[824,5333,5334,5336,5339,5341,5344,5346,5348,5350],{"class":826,"line":908},[824,5335,4697],{"class":830},[824,5337,5338],{"class":871}," emitProgress",[824,5340,941],{"class":838},[824,5342,5343],{"class":851},"progress",[824,5345,855],{"class":838},[824,5347,5060],{"class":858},[824,5349,899],{"class":838},[824,5351,917],{"class":838},[824,5353,5354,5356,5359,5361,5363,5365,5367],{"class":826,"line":920},[824,5355,923],{"class":830},[824,5357,5358],{"class":834}," now",[824,5360,929],{"class":838},[824,5362,4312],{"class":834},[824,5364,782],{"class":838},[824,5366,4317],{"class":871},[824,5368,1177],{"class":940},[824,5370,5371,5373,5375,5377,5379,5382,5384,5387,5389],{"class":826,"line":961},[824,5372,2717],{"class":1004},[824,5374,877],{"class":940},[824,5376,4317],{"class":834},[824,5378,1676],{"class":838},[824,5380,5381],{"class":834}," lastEmitTime",[824,5383,1013],{"class":838},[824,5385,5386],{"class":834}," THROTTLE_INTERVAL",[824,5388,911],{"class":940},[824,5390,5391],{"class":1004},"return\n",[824,5393,5394],{"class":826,"line":975},[824,5395,4782],{"class":940},[824,5397,5398,5401,5403],{"class":826,"line":982},[824,5399,5400],{"class":834},"  lastEmitTime",[824,5402,929],{"class":838},[824,5404,5405],{"class":834}," now\n",[824,5407,5408,5411,5413,5416,5418,5420,5422,5424,5426,5429],{"class":826,"line":1001},[824,5409,5410],{"class":834},"  eventEmitter",[824,5412,782],{"class":838},[824,5414,5415],{"class":871},"emit",[824,5417,941],{"class":940},[824,5419,2178],{"class":838},[824,5421,5343],{"class":1955},[824,5423,2178],{"class":838},[824,5425,888],{"class":838},[824,5427,5428],{"class":834}," progress",[824,5430,958],{"class":940},[824,5432,5433],{"class":826,"line":1029},[824,5434,1210],{"class":838},[730,5436],{},[733,5438,5440],{"id":5439},"cancellation-mechanism","Cancellation Mechanism",[752,5442,5444],{"id":5443},"abortcontroller-integration","AbortController Integration",[719,5446,5447,5448,5451],{},"Download engine fully supports cancellation via standard ",[748,5449,5450],{},"AbortController"," API:",[741,5453,5455],{"className":818,"code":5454,"language":820,"meta":750,"style":750},"async function startDownload(\n  url: string,\n  options: DownloadOptions,\n  signal: AbortSignal\n): Promise\u003Cvoid> {\n  \u002F\u002F Pass signal to each module\n  await parseManifest(url, { signal })\n  await downloadSegments(segments, { signal })\n  await processSegments(segments, { signal })\n  await writeFile(outputFile, { signal })\n}\n",[748,5456,5457,5468,5479,5491,5499,5514,5519,5542,5563,5584,5606],{"__ignoreMap":750},[824,5458,5459,5461,5463,5466],{"class":826,"line":827},[824,5460,1287],{"class":830},[824,5462,1290],{"class":830},[824,5464,5465],{"class":871}," startDownload",[824,5467,1130],{"class":838},[824,5469,5470,5473,5475,5477],{"class":826,"line":848},[824,5471,5472],{"class":851},"  url",[824,5474,855],{"class":838},[824,5476,1892],{"class":858},[824,5478,865],{"class":838},[824,5480,5481,5484,5486,5489],{"class":826,"line":868},[824,5482,5483],{"class":851},"  options",[824,5485,855],{"class":838},[824,5487,5488],{"class":858}," DownloadOptions",[824,5490,865],{"class":838},[824,5492,5493,5495,5497],{"class":826,"line":908},[824,5494,1315],{"class":851},[824,5496,855],{"class":838},[824,5498,1321],{"class":858},[824,5500,5501,5503,5505,5507,5510,5512],{"class":826,"line":920},[824,5502,1326],{"class":838},[824,5504,1192],{"class":858},[824,5506,1332],{"class":838},[824,5508,5509],{"class":858},"void",[824,5511,1338],{"class":838},[824,5513,917],{"class":838},[824,5515,5516],{"class":826,"line":961},[824,5517,5518],{"class":1688},"  \u002F\u002F Pass signal to each module\n",[824,5520,5521,5523,5526,5528,5531,5533,5535,5538,5540],{"class":826,"line":975},[824,5522,1189],{"class":1004},[824,5524,5525],{"class":871}," parseManifest",[824,5527,941],{"class":940},[824,5529,5530],{"class":834},"url",[824,5532,888],{"class":838},[824,5534,2758],{"class":838},[824,5536,5537],{"class":834}," signal",[824,5539,2769],{"class":838},[824,5541,958],{"class":940},[824,5543,5544,5546,5549,5551,5553,5555,5557,5559,5561],{"class":826,"line":982},[824,5545,1189],{"class":1004},[824,5547,5548],{"class":871}," downloadSegments",[824,5550,941],{"class":940},[824,5552,1062],{"class":834},[824,5554,888],{"class":838},[824,5556,2758],{"class":838},[824,5558,5537],{"class":834},[824,5560,2769],{"class":838},[824,5562,958],{"class":940},[824,5564,5565,5567,5570,5572,5574,5576,5578,5580,5582],{"class":826,"line":1001},[824,5566,1189],{"class":1004},[824,5568,5569],{"class":871}," processSegments",[824,5571,941],{"class":940},[824,5573,1062],{"class":834},[824,5575,888],{"class":838},[824,5577,2758],{"class":838},[824,5579,5537],{"class":834},[824,5581,2769],{"class":838},[824,5583,958],{"class":940},[824,5585,5586,5588,5591,5593,5596,5598,5600,5602,5604],{"class":826,"line":1029},[824,5587,1189],{"class":1004},[824,5589,5590],{"class":871}," writeFile",[824,5592,941],{"class":940},[824,5594,5595],{"class":834},"outputFile",[824,5597,888],{"class":838},[824,5599,2758],{"class":838},[824,5601,5537],{"class":834},[824,5603,2769],{"class":838},[824,5605,958],{"class":940},[824,5607,5608],{"class":826,"line":1044},[824,5609,1210],{"class":838},[719,5611,5612,855],{},[1214,5613,5614],{},"Cancellation Propagation Chain",[741,5616,5619],{"className":5617,"code":5618,"language":746},[744],"User clicks cancel button\n    │\n    ▼\nUI layer calls controller.abort()\n    │\n    ▼\n1. Set signal.aborted = true\n    │\n    ├─→ 2. Stop accepting new download tasks\n    │      └── Worker Pool stops grabbing new segments from queue\n    │\n    ├─→ 3. Interrupt ongoing fetch requests\n    │      └── fetch() throws AbortError, caught by retry mechanism\n    │\n    ├─→ 4. Stop Worker Pool\n    │      └── All Workers detect signal.aborted, exit loop\n    │\n    ├─→ 5. Clean up FFmpeg virtual filesystem\n    │      └── Delete temp files: filelist.txt, segment_*.ts, output.*\n    │\n    ├─→ 6. Release allocated memory buffers\n    │      └── Set all ArrayBuffer references to null, wait for GC\n    │\n    ├─→ 7. Discard incomplete file\n    │      └── FSA mode: call writable.abort()\n    │      └── StreamSaver mode: call writable.abort()\n    │      └── Blob mode: Don't trigger download, release Blob directly\n    │\n    └─→ 8. Reset engine state\n           └── Clear progress data, speed stats, error messages\n",[748,5620,5618],{"__ignoreMap":750},[752,5622,5624],{"id":5623},"cancellation-propagation-mechanism","Cancellation Propagation Mechanism",[719,5626,5627,5630],{},[748,5628,5629],{},"AbortSignal"," propagates layer-by-layer through entire download chain:",[741,5632,5635],{"className":5633,"code":5634,"language":746},[744],"UI Layer AbortController\n    │\n    ├──→ Segment Download Worker Pool (interrupt fetch)\n    ├──→ Segment Processing Pipeline (skip remaining segments)\n    ├──→ FFmpeg WASM (terminate remuxing)\n    └──→ File Write Stream (abort write)\n",[748,5636,5634],{"__ignoreMap":750},[719,5638,5639,5640,5643],{},"Each layer independently checks ",[748,5641,5642],{},"signal.aborted",", ensuring cancel operation responds quickly. Even when cancelling during FFmpeg remuxing, engine waits for current FFmpeg operation to complete one atomic step before terminating, avoiding virtual filesystem corruption.",[766,5645,5646],{},[719,5647,5648,5649,5651,5652,782],{},"Cancel operation especially important in ",[772,5650,65],{"href":66}," scenarios — users can cancel a specific download in queue without affecting other ongoing tasks. For queue behavior after cancellation, see ",[772,5653,5655],{"href":5654},"\u002Fdocs\u002Ffeatures\u002Fbatch-download#queue-management","Batch Download — Queue Management",[733,5657,5659],{"id":5658},"performance-benchmarks","Performance Benchmarks",[719,5661,5662],{},"Following data tested under Chrome 126 + 100Mbps network environment, for reference only:",[1425,5664,5665,5687],{},[1428,5666,5667],{},[1431,5668,5669,5672,5675,5678,5681,5684],{},[1434,5670,5671],{},"Scenario",[1434,5673,5674],{},"File Size",[1434,5676,5677],{},"Concurrency",[1434,5679,5680],{},"Download Time",[1434,5682,5683],{},"Merge Time",[1434,5685,5686],{},"Total Time",[1444,5688,5689,5709,5726,5746,5763,5781],{},[1431,5690,5691,5694,5697,5700,5703,5706],{},[1449,5692,5693],{},"Short video (TS output)",[1449,5695,5696],{},"~50MB (30 segments)",[1449,5698,5699],{},"4",[1449,5701,5702],{},"~8s",[1449,5704,5705],{},"\u003C1s",[1449,5707,5708],{},"~9s",[1431,5710,5711,5714,5716,5718,5720,5723],{},[1449,5712,5713],{},"Short video (MP4 output)",[1449,5715,5696],{},[1449,5717,5699],{},[1449,5719,5702],{},[1449,5721,5722],{},"~3s",[1449,5724,5725],{},"~11s",[1431,5727,5728,5731,5734,5737,5740,5743],{},[1449,5729,5730],{},"Long video (TS output)",[1449,5732,5733],{},"~500MB (200 segments)",[1449,5735,5736],{},"6",[1449,5738,5739],{},"~45s",[1449,5741,5742],{},"~2s",[1449,5744,5745],{},"~47s",[1431,5747,5748,5751,5753,5755,5757,5760],{},[1449,5749,5750],{},"Long video (MP4 output)",[1449,5752,5733],{},[1449,5754,5736],{},[1449,5756,5739],{},[1449,5758,5759],{},"~15s",[1449,5761,5762],{},"~60s",[1431,5764,5765,5768,5771,5774,5777,5779],{},[1449,5766,5767],{},"Very large file (TS output)",[1449,5769,5770],{},"~2GB (800 segments)",[1449,5772,5773],{},"8",[1449,5775,5776],{},"~3min",[1449,5778,5702],{},[1449,5780,5776],{},[1431,5782,5783,5786,5789,5791,5794,5797],{},[1449,5784,5785],{},"DASH audio-video separate",[1449,5787,5788],{},"~300MB video + ~30MB audio",[1449,5790,5699],{},[1449,5792,5793],{},"~30s",[1449,5795,5796],{},"~12s",[1449,5798,5799],{},"~42s",[719,5801,5802,855],{},[1214,5803,5804],{},"Influencing Factors",[1425,5806,5807,5820],{},[1428,5808,5809],{},[1431,5810,5811,5814,5817],{},[1434,5812,5813],{},"Factor",[1434,5815,5816],{},"Impact Level",[1434,5818,5819],{},"Description",[1444,5821,5822,5833,5844,5854,5864],{},[1431,5823,5824,5827,5830],{},[1449,5825,5826],{},"CDN speed",[1449,5828,5829],{},"High",[1449,5831,5832],{},"Upper limit of segment download speed",[1431,5834,5835,5838,5841],{},[1449,5836,5837],{},"Concurrent threads",[1449,5839,5840],{},"Medium",[1449,5842,5843],{},"4-6 threads usually optimal range",[1431,5845,5846,5849,5851],{},[1449,5847,5848],{},"Output format",[1449,5850,5840],{},[1449,5852,5853],{},"TS output skips FFmerge, faster merging",[1431,5855,5856,5859,5861],{},[1449,5857,5858],{},"SharedArrayBuffer",[1449,5860,5840],{},[1449,5862,5863],{},"Multi-threaded FFmpeg 40-60% faster than single-threaded",[1431,5865,5866,5869,5872],{},[1449,5867,5868],{},"Encrypted streams",[1449,5870,5871],{},"Low",[1449,5873,5874],{},"Web Crypto API hardware accelerated, minimal decryption overhead",[752,5876,5878],{"id":5877},"relationship-between-concurrency-and-performance","Relationship Between Concurrency and Performance",[741,5880,5883],{"className":5881,"code":5882,"language":746},[744],"Concurrency 1: ████████████████████████████ Slow, low bandwidth utilization\nConcurrency 2: ████████████████ Faster, basically usable\nConcurrency 4: ██████████ Fast, recommended default\nConcurrency 6: ████████ Very fast, near optimal\nConcurrency 8: ████████ About same as 6, diminishing returns\nConcurrency 12+: ████████ May trigger CDN throttling,反而 slower\n",[748,5884,5882],{"__ignoreMap":750},[1255,5886,5887],{},[719,5888,5889,5890,782],{},"Selecting TS output format can skip FFmpeg merge phase, saving 10-20% total time for very large files. TS files can be played directly with VLC, PotPlayer, IINA etc. For more troubleshooting methods on slow download speeds, see ",[772,5891,5893],{"href":5892},"\u002Fdocs\u002Ftroubleshooting\u002Fcommon-issues#slow-download-speed","Common Issues Troubleshooting — Slow Download Speed",[733,5895,5897],{"id":5896},"error-boundaries-exception-propagation","Error Boundaries & Exception Propagation",[719,5899,5900],{},"Download engine adopts layered error handling architecture, ensuring exceptions at each level are properly caught and converted to user-friendly prompts:",[741,5902,5905],{"className":5903,"code":5904,"language":746},[744],"┌─────────────────────────────────────────────┐\n│                   UI Layer                  │\n│  · Display user prompts (Toast\u002Fpopup)       │\n│  · Update download status to \"failed\"       │\n│  · Provide retry\u002Ffeedback entry points      │\n└──────────────────┬──────────────────────────┘\n                   │ Catch all exceptions\n┌──────────────────▼──────────────────────────┐\n│              Engine Facade Layer             │\n│  · Unified exception format (StreamMergeError) │\n│  · Attach context info (URL, segment index, stage) │\n│  · Decide whether retryable                 │\n└──────────────────┬──────────────────────────┘\n                   │\n    ┌──────────────┼──────────────┐\n    ▼              ▼              ▼\n┌────────┐  ┌──────────┐  ┌──────────┐\n│Download│  │Process   │  │Write     │\n│ Module │  │Module    │  │Module    │\n│        │  │          │  │          │\n│FetchErr│  │CryptoErr │  │WriteErr  │\n└────────┘  └──────────┘  └──────────┘\n",[748,5906,5904],{"__ignoreMap":750},[719,5908,5909,855],{},[1214,5910,5911],{},"Error Type Mapping",[1425,5913,5914,5929],{},[1428,5915,5916],{},[1431,5917,5918,5921,5924,5926],{},[1434,5919,5920],{},"Underlying Error",[1434,5922,5923],{},"Engine Error Type",[1434,5925,1985],{},[1434,5927,5928],{},"Retryable",[1444,5930,5931,5949,5966,5984,6001,6019,6036,6053],{},[1431,5932,5933,5938,5943,5946],{},[1449,5934,5935],{},[748,5936,5937],{},"FetchError(403)",[1449,5939,5940],{},[748,5941,5942],{},"AuthError",[1449,5944,5945],{},"\"Access denied\"",[1449,5947,5948],{},"No",[1431,5950,5951,5956,5961,5964],{},[1449,5952,5953],{},[748,5954,5955],{},"FetchError(404)",[1449,5957,5958],{},[748,5959,5960],{},"NotFoundError",[1449,5962,5963],{},"\"Resource expired\"",[1449,5965,5948],{},[1431,5967,5968,5973,5978,5981],{},[1449,5969,5970],{},[748,5971,5972],{},"FetchError(5xx)",[1449,5974,5975],{},[748,5976,5977],{},"ServerError",[1449,5979,5980],{},"\"Server error\"",[1449,5982,5983],{},"Yes",[1431,5985,5986,5991,5996,5999],{},[1449,5987,5988],{},[748,5989,5990],{},"TypeError: Failed to fetch",[1449,5992,5993],{},[748,5994,5995],{},"NetworkError",[1449,5997,5998],{},"\"Network connection failed\"",[1449,6000,5983],{},[1431,6002,6003,6008,6013,6016],{},[1449,6004,6005],{},[748,6006,6007],{},"DOMException: AbortError",[1449,6009,6010],{},[748,6011,6012],{},"CancelledError",[1449,6014,6015],{},"No prompt (silent)",[1449,6017,6018],{},"—",[1431,6020,6021,6026,6031,6034],{},[1449,6022,6023],{},[748,6024,6025],{},"CryptoError",[1449,6027,6028],{},[748,6029,6030],{},"DecryptError",[1449,6032,6033],{},"\"Decryption failed\"",[1449,6035,5948],{},[1431,6037,6038,6043,6048,6051],{},[1449,6039,6040],{},[748,6041,6042],{},"FFmpegError",[1449,6044,6045],{},[748,6046,6047],{},"MergeError",[1449,6049,6050],{},"\"Merge failed\"",[1449,6052,5948],{},[1431,6054,6055,6060,6065,6068],{},[1449,6056,6057],{},[748,6058,6059],{},"QuotaExceededError",[1449,6061,6062],{},[748,6063,6064],{},"StorageError",[1449,6066,6067],{},"\"Insufficient storage space\"",[1449,6069,5948],{},[766,6071,6072],{},[719,6073,6074,6075,6077,6078,6081,6082,782],{},"For detailed troubleshooting steps for various errors, see ",[772,6076,141],{"href":142},". For engine's known limitations and edge cases, see ",[772,6079,6080],{"href":146},"Known Issues",". For how to contribute error handling improvements to engine, see ",[772,6083,161],{"href":162},[733,6085,6087],{"id":6086},"related-documentation","Related Documentation",[1218,6089,6090,6095,6100,6105,6110,6115,6120,6125,6130,6135,6140,6146,6152,6157,6162],{},[1221,6091,6092,6094],{},[772,6093,40],{"href":41}," — HLS\u002FDASH manifest parsing and encryption detection",[1221,6096,6097,6099],{},[772,6098,60],{"href":61}," — FFmpeg WASM engine and TSToMP4Muxer",[1221,6101,6102,6104],{},[772,6103,65],{"href":66}," — Queue scheduling and concurrency control",[1221,6106,6107,6109],{},[772,6108,81],{"href":82}," — Practical application of write strategies in online tools",[1221,6111,6112,6114],{},[772,6113,86],{"href":87}," — API support across browsers and fallback strategies",[1221,6116,6117,6119],{},[772,6118,55],{"href":56}," — Local processing, zero data upload",[1221,6121,6122,6124],{},[772,6123,28],{"href":29}," — Configuration items like concurrency, output format",[1221,6126,6127,6129],{},[772,6128,166],{"href":167}," — Engine's position in overall system and module interaction",[1221,6131,6132,6134],{},[772,6133,161],{"href":162}," — Contributing code to download engine",[1221,6136,6137,6139],{},[772,6138,1495],{"href":112}," — Actual scenarios for very large file downloads",[1221,6141,6142,6145],{},[772,6143,6144],{"href":103},"Online Courses Download"," — Course video download scenarios",[1221,6147,6148,6151],{},[772,6149,6150],{"href":108},"Video Platform Downloads"," — Mainstream platform download practices",[1221,6153,6154,6156],{},[772,6155,141],{"href":142}," — Diagnosis of download failures",[1221,6158,6159,6161],{},[772,6160,6080],{"href":146}," — Known limitations of download engine",[1221,6163,6164,6166],{},[772,6165,150],{"href":151}," — High-frequency download-related questions",[6168,6169,6170],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":750,"searchDepth":848,"depth":848,"links":6172},[6173,6177,6183,6189,6195,6201,6206,6210,6213,6214],{"id":735,"depth":848,"text":736,"children":6174},[6175,6176],{"id":754,"depth":868,"text":755},{"id":785,"depth":868,"text":786},{"id":807,"depth":848,"text":808,"children":6178},[6179,6180,6181,6182],{"id":811,"depth":868,"text":812},{"id":1273,"depth":868,"text":1274},{"id":1498,"depth":868,"text":1499},{"id":1853,"depth":868,"text":1854},{"id":2065,"depth":848,"text":2066,"children":6184},[6185,6186,6187,6188],{"id":2069,"depth":868,"text":2070},{"id":2419,"depth":868,"text":2420},{"id":2535,"depth":868,"text":2536},{"id":2554,"depth":868,"text":2555},{"id":2618,"depth":848,"text":2619,"children":6190},[6191,6192,6193,6194],{"id":2631,"depth":868,"text":2632},{"id":3121,"depth":868,"text":3122},{"id":3277,"depth":868,"text":3278},{"id":3446,"depth":868,"text":3447},{"id":3556,"depth":848,"text":3557,"children":6196},[6197,6198,6199,6200],{"id":3566,"depth":868,"text":3567},{"id":3885,"depth":868,"text":3886},{"id":3895,"depth":868,"text":3896},{"id":3965,"depth":868,"text":3966},{"id":4177,"depth":848,"text":4178,"children":6202},[6203,6204,6205],{"id":4181,"depth":868,"text":4182},{"id":4683,"depth":868,"text":4684},{"id":5043,"depth":868,"text":5044},{"id":5439,"depth":848,"text":5440,"children":6207},[6208,6209],{"id":5443,"depth":868,"text":5444},{"id":5623,"depth":868,"text":5624},{"id":5658,"depth":848,"text":5659,"children":6211},[6212],{"id":5877,"depth":868,"text":5878},{"id":5896,"depth":848,"text":5897},{"id":6086,"depth":848,"text":6087},"Technical architecture details of FlowPick's download engine — segment concurrent download, AES-128 decryption, three-tier write strategy, memory safety management, and progress tracking.","md",{},{"icon":94},{"title":91,"description":6215},"un1cvNd-lIgYC5b10sO46C2tPcw3Ihove80sYX1gTQo",[6222,6224],{"title":86,"path":87,"stem":88,"description":6223,"icon":89,"children":-1},"FlowPick feature support across different browsers, including API compatibility matrix, fallback strategies, and browser selection recommendations.",{"title":102,"path":103,"stem":104,"description":6225,"icon":105,"children":-1},"Use FlowPick to save online course videos for offline learning and content backup.",1783158225905]