@@ -6,6 +6,7 @@ import { DownloadStatus, downloadStatusList, IM3u8Item, ITsItem } from "@/servic
66import { NAlert , NButton , NCard , NInput , NInputGroup , NInputGroupLabel , NProgress , NTag , NText } from "naive-ui" ;
77import { computed , defineComponent , onActivated , onMounted , reactive , ref } from "vue" ;
88import { useRoute } from "vue-router" ;
9+ import muxjs from "mux.js" ;
910
1011export default defineComponent ( {
1112 props : { } ,
@@ -30,6 +31,7 @@ export default defineComponent({
3031 const total = list . length ;
3132 const doneNum = list . filter ( li => li . status === DownloadStatus . FINISHED ) . length ;
3233 const percentage = Number ( ( ( doneNum / total ) * 100 ) . toFixed ( 2 ) ) ;
34+ const duration = list . reduce ( ( t , v ) => t + v . duration , 0 ) ;
3335 if ( tsList . value . some ( t => t . status === DownloadStatus . DOWNLOADING ) ) {
3436 status = DownloadStatus . DOWNLOADING ;
3537 } else if ( tsList . value . some ( t => t . status === DownloadStatus . ERROR ) ) {
@@ -45,6 +47,7 @@ export default defineComponent({
4547 percentage,
4648 total,
4749 doneNum,
50+ duration,
4851 } ;
4952 } ) ;
5053 return data ;
@@ -69,8 +72,16 @@ export default defineComponent({
6972 }
7073
7174 const tempArr : ITsItem [ ] = [ ] ;
72- data . split ( / \s / ) . forEach ( item => {
75+ const lines = data . split ( / \s / ) ;
76+ lines . forEach ( ( item , index ) => {
7377 if ( / ( ( \. t s ) | ( \. j p g ) | ( \. p n g ) | ( \. g i f ) | ( \. i m a g e ) ) ( \? .+ ) ? $ / i. test ( item ) ) {
78+ // 计算持续时间
79+ let duration = 0 ;
80+ const durationItem = lines [ index - 1 ] ;
81+ const extinf = "#EXTINF:" ;
82+ if ( durationItem . includes ( extinf ) ) {
83+ duration = parseFloat ( durationItem . split ( extinf ) [ 1 ] ) || 0 ;
84+ }
7485 const src = getFullUrl ( origin , item ) ;
7586 tempArr . push ( {
7687 status : DownloadStatus . WAITING ,
@@ -79,6 +90,7 @@ export default defineComponent({
7990 filePath : form . filePath ,
8091 src,
8192 file : undefined ,
93+ duration,
8294 } ) ;
8395 }
8496 } ) ;
@@ -106,27 +118,50 @@ export default defineComponent({
106118 downloadTs ( ) ;
107119 }
108120 }
109- function downloadTs ( ) {
121+ async function downloadTs ( ) {
110122 const index = tsList . value . findIndex ( v => v . status === DownloadStatus . WAITING ) ;
111123 if ( index === - 1 ) {
112124 return ;
113125 }
126+ const item = tsList . value [ index ] ;
114127 tsList . value [ index ] . status = DownloadStatus . DOWNLOADING ;
115- ajax < Buffer > ( tsList . value [ index ] . src , "arraybuffer" )
116- . then ( data => {
117- tsList . value [ index ] . status = DownloadStatus . FINISHED ;
118- tsList . value [ index ] . file = data ;
119- const m3u8 = m3u8List . value . find ( v => v . src === tsList . value [ index ] . m3u8Src ) ;
120- if ( m3u8 ?. status === DownloadStatus . FINISHED ) {
121- downloadFile ( m3u8 ) ;
122- }
123- } )
124- . catch ( ( ) => {
125- tsList . value [ index ] . status = DownloadStatus . ERROR ;
126- } )
127- . finally ( ( ) => {
128- downloadTs ( ) ;
128+ try {
129+ const data = await ajax < Buffer > ( item . src , "arraybuffer" ) ;
130+ // 转码mp4
131+ const file : Uint8Array = await new Promise ( resolve => {
132+ const { duration } = m3u8List . value . find ( v => v . src === item . m3u8Src ) ! ;
133+ const opts = duration
134+ ? {
135+ keepOriginalTimestamps : true ,
136+ duration,
137+ }
138+ : undefined ;
139+ const transmuxer = new muxjs . mp4 . Transmuxer ( opts ) ;
140+ const timer = setTimeout ( ( ) => {
141+ resolve ( data ) ;
142+ } , 2000 ) ;
143+ transmuxer . on ( "data" , ( segment : any ) => {
144+ clearTimeout ( timer ) ;
145+ const data = new Uint8Array ( segment . initSegment . byteLength + segment . data . byteLength ) ;
146+ data . set ( segment . initSegment , 0 ) ;
147+ data . set ( segment . data , segment . initSegment . byteLength ) ;
148+ resolve ( data ) ;
149+ } ) ;
150+ transmuxer . push ( new Uint8Array ( data ) ) ;
151+ transmuxer . flush ( ) ;
129152 } ) ;
153+
154+ tsList . value [ index ] . status = DownloadStatus . FINISHED ;
155+ tsList . value [ index ] . file = file ;
156+ const m3u8 = m3u8List . value . find ( v => v . src === item . m3u8Src ) ;
157+ if ( m3u8 ?. status === DownloadStatus . FINISHED ) {
158+ downloadFile ( m3u8 ) ;
159+ }
160+ } catch ( e ) {
161+ tsList . value [ index ] . status = DownloadStatus . ERROR ;
162+ } finally {
163+ downloadTs ( ) ;
164+ }
130165 }
131166
132167 // 文件下载
@@ -332,7 +367,16 @@ export default defineComponent({
332367 downloadFile ( item ) ;
333368 } }
334369 >
335- 保存视频
370+ 下载视频
371+ </ NButton >
372+ ) : item . percentage > 0 ? (
373+ < NButton
374+ class = "mar-r-3-item"
375+ onClick = { ( ) => {
376+ downloadFile ( item ) ;
377+ } }
378+ >
379+ 强制下载
336380 </ NButton >
337381 ) : null }
338382 { config . isElectron ? (
0 commit comments