3535 </div >
3636 </div >
3737
38+ <!-- 代理后链接信息 -->
39+ <div v-if =" proxyUrl && proxyUrl !== videoUrl" class =" info-section" >
40+ <div class =" section-header" >
41+ <h4 >🔄 代理后链接</h4 >
42+ <div class =" section-actions" >
43+ <button
44+ class =" copy-btn"
45+ @click =" copyToClipboard(proxyUrl, '代理后链接')"
46+ :disabled =" !proxyUrl"
47+ >
48+ <svg viewBox =" 0 0 24 24" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
49+ <rect x =" 9" y =" 9" width =" 13" height =" 13" rx =" 2" ry =" 2" stroke =" currentColor" stroke-width =" 2" />
50+ <path d =" M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" stroke =" currentColor" stroke-width =" 2" />
51+ </svg >
52+ 复制
53+ </button >
54+ <button
55+ class =" external-player-btn vlc-btn"
56+ @click =" openWithVLC(proxyUrl)"
57+ :disabled =" !proxyUrl"
58+ title =" 使用VLC播放器打开"
59+ >
60+ <svg viewBox =" 0 0 24 24" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
61+ <polygon points =" 5,3 19,12 5,21" fill =" currentColor" />
62+ </svg >
63+ VLC
64+ </button >
65+ <button
66+ class =" external-player-btn mpv-btn"
67+ @click =" openWithMPV(proxyUrl)"
68+ :disabled =" !proxyUrl"
69+ title =" 使用MPV播放器打开"
70+ >
71+ <svg viewBox =" 0 0 24 24" fill =" none" xmlns =" http://www.w3.org/2000/svg" >
72+ <circle cx =" 12" cy =" 12" r =" 10" stroke =" currentColor" stroke-width =" 2" />
73+ <polygon points =" 10,8 16,12 10,16" fill =" currentColor" />
74+ </svg >
75+ MPV
76+ </button >
77+ </div >
78+ </div >
79+ <div class =" info-content" >
80+ <div class =" url-display proxy-url" >
81+ {{ proxyUrl }}
82+ </div >
83+ </div >
84+ </div >
85+
3886 <!-- 请求头信息 -->
3987 <div class =" info-section" >
4088 <div class =" section-header" >
@@ -125,6 +173,10 @@ const props = defineProps({
125173 detectedFormat: {
126174 type: String ,
127175 default: ' '
176+ },
177+ proxyUrl: {
178+ type: String ,
179+ default: ' '
128180 }
129181})
130182
@@ -169,6 +221,11 @@ const copyAllInfo = async () => {
169221 ' 📹 视频直链:' ,
170222 props .videoUrl || ' 暂无' ,
171223 ' ' ,
224+ ... (props .proxyUrl && props .proxyUrl !== props .videoUrl ? [
225+ ' 🔄 代理后链接:' ,
226+ props .proxyUrl ,
227+ ' '
228+ ] : []),
172229 ' 📋 请求头信息:' ,
173230 headersText .value || ' 暂无' ,
174231 ' ' ,
@@ -183,6 +240,66 @@ const copyAllInfo = async () => {
183240
184241 await copyToClipboard (allInfo, ' 所有调试信息' )
185242}
243+
244+ // 使用VLC播放器打开视频
245+ const openWithVLC = (url ) => {
246+ if (! url) {
247+ Message .warning (' 视频链接为空,无法调起VLC播放器' )
248+ return
249+ }
250+
251+ try {
252+ // 使用vlc://协议,VLC会自动处理协议前缀
253+ const vlcUrl = ` vlc://${ url} `
254+
255+ // 创建隐藏的iframe来触发协议
256+ const iframe = document .createElement (' iframe' )
257+ iframe .style .display = ' none'
258+ iframe .src = vlcUrl
259+ document .body .appendChild (iframe)
260+
261+ // 短暂延迟后移除iframe
262+ setTimeout (() => {
263+ document .body .removeChild (iframe)
264+ }, 1000 )
265+
266+ Message .success (' 正在尝试调起VLC播放器...' )
267+ console .log (' 调起VLC播放器:' , vlcUrl)
268+ } catch (error) {
269+ console .error (' 调起VLC播放器失败:' , error)
270+ Message .error (' 调起VLC播放器失败,请确保已安装VLC播放器' )
271+ }
272+ }
273+
274+ // 使用MPV播放器打开视频
275+ const openWithMPV = (url ) => {
276+ if (! url) {
277+ Message .warning (' 视频链接为空,无法调起MPV播放器' )
278+ return
279+ }
280+
281+ try {
282+ // 使用mpv://协议,MPV会自动处理协议前缀
283+ const mpvUrl = ` mpv://${ url} `
284+
285+ // 创建隐藏的iframe来触发协议
286+ const iframe = document .createElement (' iframe' )
287+ iframe .style .display = ' none'
288+ iframe .src = mpvUrl
289+ document .body .appendChild (iframe)
290+
291+ // 短暂延迟后移除iframe
292+ setTimeout (() => {
293+ document .body .removeChild (iframe)
294+ }, 1000 )
295+
296+ Message .success (' 正在尝试调起MPV播放器...' )
297+ console .log (' 调起MPV播放器:' , mpvUrl)
298+ } catch (error) {
299+ console .error (' 调起MPV播放器失败:' , error)
300+ Message .error (' 调起MPV播放器失败,请确保已安装MPV播放器' )
301+ }
302+ }
186303 </script >
187304
188305<style scoped>
@@ -269,6 +386,12 @@ const copyAllInfo = async () => {
269386 border-bottom : 1px solid #e9ecef ;
270387}
271388
389+ .section-actions {
390+ display : flex ;
391+ align-items : center ;
392+ gap : 8px ;
393+ }
394+
272395.section-header h4 {
273396 margin : 0 ;
274397 font-size : 14px ;
@@ -320,6 +443,56 @@ const copyAllInfo = async () => {
320443 color : #495057 ;
321444}
322445
446+ .proxy-url {
447+ background : #e8f5e8 ;
448+ border-color : #4caf50 ;
449+ color : #2e7d32 ;
450+ }
451+
452+ .external-player-btn {
453+ display : flex ;
454+ align-items : center ;
455+ gap : 4px ;
456+ padding : 4px 8px ;
457+ border : none ;
458+ border-radius : 4px ;
459+ cursor : pointer ;
460+ font-size : 12px ;
461+ font-weight : 500 ;
462+ transition : all 0.2s ;
463+ }
464+
465+ .vlc-btn {
466+ background : #ff6b35 ;
467+ color : white ;
468+ }
469+
470+ .vlc-btn :hover:not (:disabled ) {
471+ background : #e55a2b ;
472+ transform : translateY (-1px );
473+ }
474+
475+ .mpv-btn {
476+ background : #8e24aa ;
477+ color : white ;
478+ }
479+
480+ .mpv-btn :hover:not (:disabled ) {
481+ background : #7b1fa2 ;
482+ transform : translateY (-1px );
483+ }
484+
485+ .external-player-btn :disabled {
486+ background : #6c757d ;
487+ cursor : not-allowed ;
488+ transform : none ;
489+ }
490+
491+ .external-player-btn svg {
492+ width : 14px ;
493+ height : 14px ;
494+ }
495+
323496.headers-display {
324497 background : #f8f9fa ;
325498 border : 1px solid #e9ecef ;
@@ -424,8 +597,15 @@ const copyAllInfo = async () => {
424597 gap : 8px ;
425598 }
426599
427- .copy-btn {
600+ .section-actions {
428601 align-self : flex-end ;
602+ flex-wrap : wrap ;
603+ }
604+
605+ .copy-btn ,
606+ .external-player-btn {
607+ font-size : 11px ;
608+ padding : 3px 6px ;
429609 }
430610
431611 .url-display ,
0 commit comments