Forráskód Böngészése

Merge branch 'iteration-20240522-download' into jenkins-test

lex 1 éve
szülő
commit
6100dee18a

+ 181 - 77
src/views/courseware-play/component/audio-item/index.tsx

@@ -65,6 +65,8 @@ export default defineComponent({
     const canvasRef: any = ref();
     const audioRef: any = ref();
     const contetRef = ref();
+    // const audioSlider =
+    //   'audioSlider' + Date.now() + Math.floor(Math.random() * 100);
 
     watch(
       () => props.show,
@@ -223,6 +225,7 @@ export default defineComponent({
       let previousBytesLoaded = 0;
       let timer: any = null;
       let previousTime = Date.now();
+      let buffterCatchArray = [] as any; // 缓存数据显示
       let isWaiting = false;
 
       // 缓存检测状态
@@ -239,7 +242,7 @@ export default defineComponent({
         }, 1500);
       }
 
-      function buffterCatch() {
+      function buffterCatch(time = 0) {
         // 设定一个计时器,检查是否在指定的时间内再次触发了progress事件
         bufferTimeout = setTimeout(() => {
           if (isBuffering) {
@@ -248,7 +251,7 @@ export default defineComponent({
             isBuffering = false;
             data.speedInKbps = '';
           }
-        }, BUFFER_CHECK_INTERVAL);
+        }, time || BUFFER_CHECK_INTERVAL);
       }
 
       function resetBuffterCatch() {
@@ -262,101 +265,199 @@ export default defineComponent({
         buffterCatch();
       }
 
-      element.addEventListener('loadedmetadata', () => {
-        // 获取视频总时长
+      /**
+       * 格式化视屏播放有效时间 - 合并区间
+       * @param intervals [[], []]
+       * @example [[4, 8],[0, 4],[10, 30]]
+       * @returns [[0, 8], [10, 30]]
+       */
+      const formatEffectiveTime = (intervals: any[]) => {
+        const res: any = [];
+        intervals.sort((a, b) => a[0] - b[0]);
+        let prev = intervals[0];
+        for (let i = 1; i < intervals.length; i++) {
+          const cur = intervals[i];
+          if (prev[1] >= cur[0]) {
+            // 有重合
+            prev[1] = Math.max(cur[1], prev[1]);
+          } else {
+            // 不重合,prev推入res数组
+            res.push(prev);
+            prev = cur; // 更新 prev
+          }
+        }
+        res.push(prev);
+        return res;
+      };
+
+      console.log(element, 'element');
+
+      // 获取视频总时长
+      let noData = false;
+      const onProgress = () => {
         const duration = element.duration;
-        element.addEventListener('progress', () => {
-          const currentTime = Date.now();
-          const buffered = element.buffered;
-          let currentBytesLoaded = 0;
-
-          // 计算视频已缓存的总时长
-          let cachedDuration = 0;
-          if (buffered.length > 0) {
-            for (let i = 0; i < buffered.length; i++) {
-              currentBytesLoaded += buffered.end(i) - buffered.start(i);
-              cachedDuration += buffered.end(i) - buffered.start(i);
-            }
-            currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
+        const currentTime = Date.now();
+        const buffered = element.buffered;
+        let currentBytesLoaded = 0;
+        let currentLength = 0;
+
+        // 计算视频已缓存的总时长
+        let cachedDuration = 0;
+        if (buffered.length > 0) {
+          for (let i = 0; i < buffered.length; i++) {
+            currentBytesLoaded += buffered.end(i) - buffered.start(i);
+            cachedDuration += buffered.end(i) - buffered.start(i);
+            buffterCatchArray = formatEffectiveTime([
+              ...buffterCatchArray,
+              [buffered.start(i), buffered.end(i)]
+            ]);
           }
+          // for (let i = 0; i < buffered.length; i++) {
+          //   // 寻找当前时间之后最近的点
+          //   if (buffered.start(buffered.length - 1 - i) < element.currentTime) {
+          //     currentLength =
+          //       (buffered.end(buffered.length - 1 - i) / duration) * 100;
+          //     break;
+          //   }
+          // }
+          currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
+        }
 
-          // 计算未缓存的时间段
-          const uncachedDuration = duration - cachedDuration;
-          // console.log(uncachedDuration, duration, cachedDuration, 'duration');
-          // 如果存在未缓存的时间段,可以根据具体情况做出相应处理
-          if (uncachedDuration > 0) {
-            // console.log(
-            //   'progress',
-            //   currentBytesLoaded,
-            //   previousBytesLoaded,
-            //   currentBytesLoaded > previousBytesLoaded
-            // );
-            if (currentBytesLoaded > previousBytesLoaded && data.isOnline) {
-              const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒
-              const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值
-              const speed = bytesDiff / timeDiff; // 字节每秒
-
-              if (!element.paused) {
-                const kbps = speed / 1024;
-                const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数
-                if (kbps > 1024) {
-                  data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`;
-                } else {
-                  data.speedInKbps = `${Number(speedInKbps)} KB/s`;
-                }
+        // 计算未缓存的时间段
+        const uncachedDuration = duration - cachedDuration;
+        let uncachedTime = true; // 没有缓存时间
+        buffterCatchArray.forEach((item: any) => {
+          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
+            uncachedTime = false;
+          }
+        });
+        // console.log(
+        //   uncachedTime,
+        //   duration,
+        //   cachedDuration,
+        //   'duration',
+        //   buffterCatchArray,
+        //   element.currentTime,
+        //   currentLength + '%',
+        //   isWaiting,
+        //   currentBytesLoaded <= previousBytesLoaded
+        // );
+
+        const isNoBuffer = currentBytesLoaded <= previousBytesLoaded;
+        // console.log(
+        //   'progress',
+        //   currentBytesLoaded,
+        //   previousBytesLoaded,
+        //   currentBytesLoaded > previousBytesLoaded
+        // );
+        // 计算未缓存的时间段
+        // const uncachedDuration = duration - cachedDuration;
+        // console.log(uncachedDuration, duration, cachedDuration, 'duration');
+        // 如果存在未缓存的时间段,可以根据具体情况做出相应处理
+        if (uncachedDuration > 0) {
+          if (currentBytesLoaded > previousBytesLoaded && data.isOnline) {
+            const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒
+            const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值
+            const speed = bytesDiff / timeDiff; // 字节每秒
+
+            if (!element.paused) {
+              const kbps = speed / 1024;
+              const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数
+              if (kbps > 1024) {
+                data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`;
+              } else {
+                data.speedInKbps = `${Number(speedInKbps)} KB/s`;
               }
 
-              previousBytesLoaded = currentBytesLoaded;
-              previousTime = currentTime;
-            }
-
-            if (!element.paused && data.isOnline) {
               // 如果1秒钟没有返回就重置数据
               clearTimeout(timer);
               resetDownloadSpeed();
             }
 
-            if (!isWaiting) {
-              resetBuffterCatch();
-            }
-          } else {
-            resetBuffterCatch();
+            previousBytesLoaded = currentBytesLoaded;
+            previousTime = currentTime;
+            noData = false;
           }
-        });
 
-        element.addEventListener('waiting', () => {
-          console.log('waiting');
-          isWaiting = true;
-
-          if (!element.paused && data.isOnline) {
+          if (isNoBuffer && !uncachedTime) {
             // 如果1秒钟没有返回就重置数据
-            clearTimeout(timer);
-            resetDownloadSpeed();
+
+            if (!noData) {
+              clearTimeout(timer);
+              clearTimeout(bufferTimeout);
+              setTimeout(() => {
+                if (isBuffering) {
+                  // 如果计时器到达且isBuffering仍为true,则认为缓存停止
+                  console.log('停止缓存数据');
+                  isBuffering = false;
+                  data.speedInKbps = '';
+                }
+              }, 800);
+            }
+
+            noData = true;
           }
 
-          // 如果有缓存检测计时器,则清除它
-          if (bufferTimeout) {
-            clearTimeout(bufferTimeout);
+          if (element.paused || !data.isOnline) {
+            clearTimeout(timer);
+            data.speedInKbps = '';
           }
-        });
-        element.addEventListener('canplay', () => {
-          console.log('canplay');
-          isWaiting = false;
-          resetBuffterCatch();
-        });
 
-        element.addEventListener('pause', () => {
+          if (!isWaiting) {
+            resetBuffterCatch();
+          }
+        } else {
           clearTimeout(timer);
-          // 如果有缓存检测计时器,则清除它
-          if (bufferTimeout) {
-            clearTimeout(bufferTimeout);
+          buffterCatch(1000);
+        }
+      };
+
+      const onWaiting = () => {
+        console.log('waiting');
+        isWaiting = true;
+        let uncachedTime = true; // 没有缓存时间
+        buffterCatchArray.forEach((item: any) => {
+          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
+            uncachedTime = false;
           }
-          data.speedInKbps = '';
         });
-        // element.addEventListener('error', () => {
-        //   element.pause();
-        // });
-      });
+
+        if (!element.paused && data.isOnline && uncachedTime) {
+          // 如果1秒钟没有返回就重置数据
+          clearTimeout(timer);
+          resetDownloadSpeed();
+        }
+
+        // 如果有缓存检测计时器,则清除它
+        if (bufferTimeout) {
+          clearTimeout(bufferTimeout);
+        }
+      };
+
+      const onCanplay = () => {
+        console.log('canplay');
+        isWaiting = false;
+        resetBuffterCatch();
+      };
+
+      const onPause = () => {
+        clearTimeout(timer);
+        // 如果有缓存检测计时器,则清除它
+        if (bufferTimeout) {
+          clearTimeout(bufferTimeout);
+        }
+        data.speedInKbps = '';
+      };
+
+      // element.removeEventListener('progress', onProgress);
+      // element.removeEventListener('waiting', onWaiting);
+      // element.removeEventListener('canplay', onCanplay);
+      // element.removeEventListener('pause', onPause);
+
+      element.addEventListener('progress', onProgress);
+      element.addEventListener('waiting', onWaiting);
+      element.addEventListener('canplay', onCanplay);
+      element.addEventListener('pause', onPause);
     };
 
     const onChangeOnlineStatus = (val: any) => {
@@ -407,6 +508,9 @@ export default defineComponent({
                 console.log('pause');
                 data.playState = 'pause';
               }}
+              onProgress={() => {
+                console.log('progress');
+              }}
               onEnded={onEnded}
               crossorigin="anonymous"
               playsinline="false"></audio>

+ 191 - 73
src/views/courseware-play/component/video-item/index.tsx

@@ -218,6 +218,10 @@ export default defineComponent({
           emit('error');
           console.log(e, 'error');
         });
+
+        videoItem.value.on('progress', (e: any) => {
+          console.log(e, 'progress');
+        });
       }
     };
 
@@ -232,6 +236,9 @@ export default defineComponent({
         } else {
           videoItem.value.pause();
         }
+        nextTick(() => {
+          calculateSpeed(videoRef.value);
+        });
       }
     );
     watch(
@@ -245,6 +252,7 @@ export default defineComponent({
       let previousBytesLoaded = 0;
       let timer: any = null;
       let previousTime = Date.now();
+      let buffterCatchArray = [] as any; // 缓存数据显示
       let isWaiting = false;
 
       // 缓存检测状态
@@ -261,7 +269,7 @@ export default defineComponent({
         }, 1500);
       }
 
-      function buffterCatch() {
+      function buffterCatch(time = 0) {
         // 设定一个计时器,检查是否在指定的时间内再次触发了progress事件
         bufferTimeout = setTimeout(() => {
           if (isBuffering) {
@@ -270,7 +278,7 @@ export default defineComponent({
             isBuffering = false;
             data.speedInKbps = '';
           }
-        }, BUFFER_CHECK_INTERVAL);
+        }, time || BUFFER_CHECK_INTERVAL);
       }
 
       function resetBuffterCatch() {
@@ -284,98 +292,208 @@ export default defineComponent({
         buffterCatch();
       }
 
-      element.addEventListener('loadedmetadata', () => {
-        // 获取视频总时长
+      /**
+       * 格式化视屏播放有效时间 - 合并区间
+       * @param intervals [[], []]
+       * @example [[4, 8],[0, 4],[10, 30]]
+       * @returns [[0, 8], [10, 30]]
+       */
+      const formatEffectiveTime = (intervals: any[]) => {
+        const res: any = [];
+        intervals.sort((a, b) => a[0] - b[0]);
+        let prev = intervals[0];
+        for (let i = 1; i < intervals.length; i++) {
+          const cur = intervals[i];
+          if (prev[1] >= cur[0]) {
+            // 有重合
+            prev[1] = Math.max(cur[1], prev[1]);
+          } else {
+            // 不重合,prev推入res数组
+            res.push(prev);
+            prev = cur; // 更新 prev
+          }
+        }
+        res.push(prev);
+        return res;
+      };
+
+      // 获取视频总时长
+      let noData = false;
+      const onProgress = () => {
         const duration = element.duration;
+        const currentTime = Date.now();
+        const buffered = element.buffered;
+        let currentBytesLoaded = 0;
+        let currentLength = 0;
+
+        // 计算视频已缓存的总时长
+        let cachedDuration = 0;
+        if (buffered.length > 0) {
+          for (let i = 0; i < buffered.length; i++) {
+            currentBytesLoaded += buffered.end(i) - buffered.start(i);
+            cachedDuration += buffered.end(i) - buffered.start(i);
+            buffterCatchArray = formatEffectiveTime([
+              ...buffterCatchArray,
+              [buffered.start(i), buffered.end(i)]
+            ]);
+          }
+          // for (let i = 0; i < buffered.length; i++) {
+          //   // 寻找当前时间之后最近的点
+          //   if (buffered.start(buffered.length - 1 - i) < element.currentTime) {
+          //     currentLength =
+          //       (buffered.end(buffered.length - 1 - i) / duration) * 100;
+          //     break;
+          //   }
+          // }
+          currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
+        }
 
-        element.addEventListener('progress', () => {
-          const currentTime = Date.now();
-          const buffered = element.buffered;
-          let currentBytesLoaded = 0;
-
-          // 计算视频已缓存的总时长
-          let cachedDuration = 0;
-          if (buffered.length > 0) {
-            for (let i = 0; i < buffered.length; i++) {
-              currentBytesLoaded += buffered.end(i) - buffered.start(i);
-              cachedDuration += buffered.end(i) - buffered.start(i);
-            }
-            currentBytesLoaded *= element.duration * element.seekable.end(0); // 更精确地近似字节加载量
+        // 计算未缓存的时间段
+        const uncachedDuration = duration - cachedDuration;
+        let uncachedTime = true; // 没有缓存时间
+        buffterCatchArray.forEach((item: any) => {
+          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
+            uncachedTime = false;
           }
+        });
+        if (duration) {
+          // const sliderDom: any = document.querySelector(
+          //   '#' + audioSlider + ' .n-slider'
+          // );
+          // if (sliderDom) {
+          //   sliderDom.style.setProperty(
+          //     '--catch-width',
+          //     uncachedDuration > 0 ? `${currentLength}%` : 'calc(100% + 17px)'
+          //   );
+          // }
+          console.log(
+            uncachedTime,
+            duration,
+            cachedDuration,
+            'duration',
+            buffterCatchArray,
+            element.currentTime,
+            currentLength + '%',
+            isWaiting,
+            currentBytesLoaded <= previousBytesLoaded
+          );
+        }
 
-          // 计算未缓存的时间段
-          const uncachedDuration = duration - cachedDuration;
-          // console.log(uncachedDuration, duration, cachedDuration, 'duration');
-          // 如果存在未缓存的时间段,可以根据具体情况做出相应处理
-          if (uncachedDuration > 0) {
-            if (currentBytesLoaded > previousBytesLoaded && data.isOnline) {
-              const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒
-              const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值
-              const speed = bytesDiff / timeDiff; // 字节每秒
-
-              console.log(timeDiff, bytesDiff, speed);
-
-              if (!element.paused) {
-                const kbps = speed / 1024;
-                const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数
-                if (kbps > 1024) {
-                  data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`;
-                } else {
-                  data.speedInKbps = `${Number(speedInKbps)} KB/s`;
-                }
+        const isNoBuffer = currentBytesLoaded <= previousBytesLoaded;
+        // console.log(
+        //   'progress',
+        //   currentBytesLoaded,
+        //   previousBytesLoaded,
+        //   currentBytesLoaded > previousBytesLoaded
+        // );
+        // 计算未缓存的时间段
+        // const uncachedDuration = duration - cachedDuration;
+        // console.log(uncachedDuration, duration, cachedDuration, 'duration');
+        // 如果存在未缓存的时间段,可以根据具体情况做出相应处理
+        if (uncachedDuration > 0) {
+          if (currentBytesLoaded > previousBytesLoaded && data.isOnline) {
+            const timeDiff = (currentTime - previousTime) / 1000; // 时间差转换为秒
+            const bytesDiff = currentBytesLoaded - previousBytesLoaded; // 字节差值
+            const speed = bytesDiff / timeDiff; // 字节每秒
+
+            if (!element.paused) {
+              const kbps = speed / 1024;
+              const speedInKbps = kbps.toFixed(2); // 转换为千字节每秒并保留两位小数
+              if (kbps > 1024) {
+                data.speedInKbps = `${Number((kbps / 1024).toFixed(2))} M/s`;
+              } else {
+                data.speedInKbps = `${Number(speedInKbps)} KB/s`;
               }
 
-              previousBytesLoaded = currentBytesLoaded;
-              previousTime = currentTime;
-            }
-
-            if (!element.paused && data.isOnline) {
               // 如果1秒钟没有返回就重置数据
               clearTimeout(timer);
               resetDownloadSpeed();
             }
 
-            if (!isWaiting) {
-              resetBuffterCatch();
-            }
-          } else {
-            resetBuffterCatch();
+            previousBytesLoaded = currentBytesLoaded;
+            previousTime = currentTime;
+            noData = false;
           }
-        });
 
-        element.addEventListener('waiting', () => {
-          console.log('waiting');
-          isWaiting = true;
-          if (!element.paused && data.isOnline) {
+          if (isNoBuffer && !uncachedTime) {
             // 如果1秒钟没有返回就重置数据
-            clearTimeout(timer);
-            resetDownloadSpeed();
+
+            if (!noData) {
+              clearTimeout(timer);
+              clearTimeout(bufferTimeout);
+              setTimeout(() => {
+                if (isBuffering) {
+                  // 如果计时器到达且isBuffering仍为true,则认为缓存停止
+                  console.log('停止缓存数据');
+                  isBuffering = false;
+                  data.speedInKbps = '';
+                }
+              }, 800);
+            }
+
+            noData = true;
           }
 
-          // 如果有缓存检测计时器,则清除它
-          if (bufferTimeout) {
-            clearTimeout(bufferTimeout);
+          if (element.paused || !data.isOnline) {
+            clearTimeout(timer);
+            data.speedInKbps = '';
           }
-        });
-        element.addEventListener('canplay', () => {
-          console.log('canplay');
-          isWaiting = false;
-          resetBuffterCatch();
-        });
 
-        element.addEventListener('pause', () => {
+          if (!isWaiting) {
+            resetBuffterCatch();
+          }
+        } else {
           clearTimeout(timer);
-          // 如果有缓存检测计时器,则清除它
-          if (bufferTimeout) {
-            clearTimeout(bufferTimeout);
+          buffterCatch(1000);
+        }
+      };
+
+      const onWaiting = () => {
+        console.log('waiting');
+        isWaiting = true;
+        let uncachedTime = true; // 没有缓存时间
+        buffterCatchArray.forEach((item: any) => {
+          if (element.currentTime >= item[0] && uncachedTime <= item[1]) {
+            uncachedTime = false;
           }
-          data.speedInKbps = '';
         });
-        // element.addEventListener('error', () => {
-        //   element.pause();
-        //   videoItem.value.pause();
-        // });
-      });
+
+        if (!element.paused && data.isOnline && uncachedTime) {
+          // 如果1秒钟没有返回就重置数据
+          clearTimeout(timer);
+          resetDownloadSpeed();
+        }
+
+        // 如果有缓存检测计时器,则清除它
+        if (bufferTimeout) {
+          clearTimeout(bufferTimeout);
+        }
+      };
+
+      const onCanplay = () => {
+        console.log('canplay');
+        isWaiting = false;
+        resetBuffterCatch();
+      };
+
+      const onPause = () => {
+        clearTimeout(timer);
+        // 如果有缓存检测计时器,则清除它
+        if (bufferTimeout) {
+          clearTimeout(bufferTimeout);
+        }
+        data.speedInKbps = '';
+      };
+
+      element.removeEventListener('progress', onProgress);
+      element.removeEventListener('waiting', onWaiting);
+      element.removeEventListener('canplay', onCanplay);
+      element.removeEventListener('pause', onPause);
+
+      element.addEventListener('progress', onProgress);
+      element.addEventListener('waiting', onWaiting);
+      element.addEventListener('canplay', onCanplay);
+      element.addEventListener('pause', onPause);
     };
 
     const onChangeOnlineStatus = (val: any) => {