feat: 浏览器端 P2P 取清单/预览增加进度与超时提示
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import type { TorrentFileEntry } from '~/types/api'
|
||||
import { readFileBytesClient } from '~/utils/clientTorrent'
|
||||
import { formatBytes } from '~/utils/format'
|
||||
import { readFileBytesClient, type FileProgress } from '~/utils/clientTorrent'
|
||||
|
||||
const props = defineProps<{
|
||||
infoHash: string
|
||||
@@ -15,6 +16,8 @@ const emit = defineEmits<{ close: []; 'update:index': [value: number] }>()
|
||||
const status = ref<'loading' | 'ok' | 'err'>('loading')
|
||||
const errorText = ref('')
|
||||
const src = ref('')
|
||||
const progress = ref(0)
|
||||
const progressText = ref('')
|
||||
let objectUrl = ''
|
||||
|
||||
const MIME: Record<string, string> = {
|
||||
@@ -50,10 +53,18 @@ async function load() {
|
||||
revoke()
|
||||
src.value = ''
|
||||
errorText.value = ''
|
||||
progress.value = 0
|
||||
progressText.value = ''
|
||||
status.value = 'loading'
|
||||
try {
|
||||
// 优先在用户浏览器里用 WebRTC 从 P2P 网络直接拉取图片字节(不经过 Vercel/Serverless)
|
||||
const bytes = await readFileBytesClient(props.magnet, current.value?.path || '', 25000)
|
||||
const bytes = await readFileBytesClient(props.magnet, current.value?.path || '', {
|
||||
timeoutMs: 25000,
|
||||
onProgress: (p: FileProgress) => {
|
||||
progress.value = p.progress
|
||||
progressText.value = p.message
|
||||
}
|
||||
})
|
||||
const mime = MIME[extOf(current.value?.path || '')] || 'application/octet-stream'
|
||||
objectUrl = URL.createObjectURL(new Blob([bytes], { type: mime }))
|
||||
src.value = objectUrl
|
||||
@@ -119,8 +130,9 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
|
||||
<div class="lightbox-bd">
|
||||
<div v-if="status === 'loading'" class="empty">
|
||||
<span class="spin" /> 正在从做种节点拉取这张图片,取决于对方的上传速度…
|
||||
<div v-if="status === 'loading'" class="empty stack sm">
|
||||
<span class="spin" /> {{ progressText || '正在通过 WebRTC 从做种节点拉取图片…' }}
|
||||
<div v-if="progress > 0" class="bar"><i :style="{ width: (progress * 100).toFixed(0) + '%' }" /></div>
|
||||
</div>
|
||||
<div v-else-if="status === 'err'" class="stack sm" style="padding: 22px">
|
||||
<div class="note err">{{ errorText }}</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import type { TorrentFileEntry, TorrentView } from '~/types/api'
|
||||
import { resolveMetadataClient } from '~/utils/clientTorrent'
|
||||
import { resolveMetadataClient, type ResolveProgress } from '~/utils/clientTorrent'
|
||||
|
||||
const props = defineProps<{
|
||||
torrent: TorrentView
|
||||
@@ -12,6 +12,7 @@ const emit = defineEmits<{ resolved: [payload: { files: TorrentFileEntry[]; size
|
||||
|
||||
const local = ref<TorrentView>({ ...props.torrent })
|
||||
const resolving = ref(false)
|
||||
const resolveStatus = ref('')
|
||||
const showTrackers = ref(false)
|
||||
|
||||
watch(
|
||||
@@ -61,6 +62,7 @@ function applyResolved(res: { files: TorrentFileEntry[]; size: number; name: str
|
||||
|
||||
async function doResolve() {
|
||||
resolving.value = true
|
||||
resolveStatus.value = ''
|
||||
try {
|
||||
// 服务端先尝试(缓存服务取清单,自托管还会走 P2P),成功即返回并落库
|
||||
const res = await $fetch<{ files: TorrentFileEntry[]; size: number; name: string }>(
|
||||
@@ -72,7 +74,12 @@ async function doResolve() {
|
||||
} catch {
|
||||
// 服务端无法走 P2P(如 Vercel/Serverless)→ 回退到浏览器端 WebRTC 直接解析
|
||||
try {
|
||||
const meta = await resolveMetadataClient(local.value.magnet, 30000)
|
||||
const meta = await resolveMetadataClient(local.value.magnet, {
|
||||
timeoutMs: 30000,
|
||||
onProgress: (p: ResolveProgress) => {
|
||||
resolveStatus.value = p.message
|
||||
}
|
||||
})
|
||||
applyResolved(meta)
|
||||
pushToast('ok', '通过浏览器 P2P 解析文件清单', `共 ${meta.files.length} 个文件 / ${formatBytes(meta.size)}`)
|
||||
} catch (err2) {
|
||||
@@ -165,6 +172,8 @@ onMounted(() => {
|
||||
文件清单里有 {{ previewImages.length }} 张图片可以点「预览」直接看:只会按需拉取这几张图所在的分片,不会下载整个种子。
|
||||
</div>
|
||||
|
||||
<div v-if="resolving && resolveStatus" class="note warn">{{ resolveStatus }}</div>
|
||||
|
||||
<div class="panel">
|
||||
<div class="panel-bd tight">
|
||||
<FileTable
|
||||
|
||||
Reference in New Issue
Block a user