Ver código fonte

feat(video_play): 增加音频文件支持并优化随机播放功能

- 在视频播放页面添加文件类型筛选功能,支持仅视频、仅音频和全部文件类型
- 实现加权随机选择算法,根据文件权重进行随机播放
- 修改文件扫描逻辑,支持音频文件格式并递归扫描子目录
- 优化 MD5 计算过程,添加文件路径和计算进度的打印信息
tianyunperfect 3 meses atrás
pai
commit
374f4f6650
2 arquivos alterados com 79 adições e 43 exclusões
  1. 41 10
      video_play/index.html
  2. 38 33
      video_play/main.py

+ 41 - 10
video_play/index.html

@@ -14,13 +14,20 @@
             <el-main>
                 <div style="margin-bottom: 20px; display: flex; align-items: center; gap: 20px; flex-wrap: nowrap;">
                     <el-button @click="getRandomVideo" type="primary">随机播放</el-button>
-                    <el-switch v-model="loopMode" active-text="自动连播" inactive-text="单次播放"></el-switch>
-                    <el-switch v-model="infiniteLoop" active-text="无限循环" inactive-text="正常模式"
-                        @change="toggleInfiniteLoop" style="flex-shrink: 0;">
+                    <el-radio-group v-model="selectedFileType" size="mini" style="margin-left: 10px;">
+                        <el-radio-button label="video">视频</el-radio-button>
+                        <el-radio-button label="audio">音频</el-radio-button>
+                        <el-radio-button label="all">全部</el-radio-button>
+                    </el-radio-group>
+                    <el-switch v-model="loopMode" active-text="连播" active-color="#13ce66" inactive-color="#ff4949"
+                        style="margin-left: 15px;"></el-switch>
+
+                    <el-switch v-model="infiniteLoop" active-text="循环播放" @change="toggleInfiniteLoop"
+                        style="flex-shrink: 0;">
                     </el-switch>
                     <div v-if="currentFile" style="display: flex; align-items: center; flex-shrink: 0;">
                         <span style="margin-right: 10px;">当前播放:</span>
-                        <el-tag type="info">{{ currentFile.filename }}</el-tag>
+                        <div style="font-weight: bold;">{{ currentFile.filename }}</div>
                         <span style="margin-left: 15px; margin-right: 10px;">权重:</span>
                         <el-input-number v-model="currentFile.weight" :min="0" :max="10" size="mini"
                             @change="updateWeight(currentFile)" style="width: 100px;">
@@ -36,7 +43,7 @@
             <!-- 视频列表 -->
             <el-aside width="450px" style="background: #f5f5f5; height: 100vh;">
                 <h3 style="margin-bottom: 15px;">视频列表(双击播放)</h3>
-                <el-table :data="files" stripe height="calc(100vh - 60px)" @row-dblclick="playSelected">
+                <el-table :data="filteredFiles" stripe height="calc(100vh - 60px)" @row-dblclick="playSelected">
                     <el-table-column prop="filename" label="文件名"></el-table-column>
                     <el-table-column label="权重" width="150">
                         <template slot-scope="{row}">
@@ -64,6 +71,8 @@
                     currentVideoMD5: '',
                     loopMode: true,
                     infiniteLoop: false
+                    ,
+                    selectedFileType: 'video'
                 }
             },
             mounted() {
@@ -72,10 +81,32 @@
             computed: {
                 currentFile() {
                     return this.files.find(file => file.md5 === this.currentVideoMD5)
-                }
+                },
+                filteredFiles() {
+                    const videoExts = ['mp4', 'avi', 'mov', 'mkv'];
+                    const audioExts = ['aac', 'mp3', 'flac'];
+
+                    return this.files.filter(file => {
+                        const ext = file.filename.split('.').pop().toLowerCase();
+                        if (this.selectedFileType === 'video') return videoExts.includes(ext);
+                        if (this.selectedFileType === 'audio') return audioExts.includes(ext);
+                        return true;
+                    });
+                },
             },
             methods: {
-                async fetchFiles() {
+                // 加权随机选择方法
+                getWeightedRandom(files) {
+                    const totalWeight = files.reduce((sum, file) => sum + (file.weight || 1), 0);
+                    const random = Math.random() * totalWeight;
+                    let currentSum = 0;
+
+                    for (const file of files) {
+                        currentSum += file.weight || 1;
+                        if (random <= currentSum) return file;
+                    }
+                    return files[Math.floor(Math.random() * files.length)];
+                }, async fetchFiles() {
                     const res = await axios.get('/files')
                     this.files = res.data
                 },
@@ -117,9 +148,9 @@
                             return this.playCurrent()
                         }
 
-                        const res = await axios.get('/random')
-                        this.currentVideoMD5 = res.data.md5
-                        this.currentVideo = `/play/${res.data.md5}`
+                        const res = this.getWeightedRandom(this.filteredFiles);
+                        this.currentVideoMD5 = res.md5
+                        this.currentVideo = `/play/${res.md5}`
 
                         this.$nextTick(() => {
                             const player = this.$refs.videoPlayer

+ 38 - 33
video_play/main.py

@@ -30,6 +30,8 @@ def save_md5_cache(cache):
 
 def compute_md5(filepath):
     """计算文件的MD5值"""
+    # 打印文件名,和前缀:正在计算
+    print(f"正在计算文件{filepath}的MD5值...")
     hash_md5 = hashlib.md5()
     with open(filepath, "rb") as f:
         for chunk in iter(lambda: f.read(8192), b""):
@@ -37,45 +39,48 @@ def compute_md5(filepath):
     return hash_md5.hexdigest()
 
 def scan_files():
-    """扫描视频文件并维护MD5缓存"""
+    """扫描视频文件并维护MD5缓存(支持子目录)"""
     cache = load_md5_cache()
     updated = False
     files = []
-    
-    for filename in os.listdir(VIDEO_DIR):
-        # 过滤非视频文件
-        if filename.split('.')[-1].lower() not in ['mp4', 'avi', 'mov', 'mkv']:
-            continue
-        
-        filepath = os.path.join(VIDEO_DIR, filename)
-        if not os.path.isfile(filepath):
-            continue
-        
-        try:
-            stat = os.stat(filepath)
-            current_size = stat.st_size
-            current_mtime = stat.st_mtime
-            
-            # 检查缓存有效性
-            if filename in cache:
-                cached_size, cached_mtime, cached_md5 = cache[filename]
-                if cached_size == current_size and cached_mtime == current_mtime:
-                    files.append({'filename': filename, 'md5': cached_md5, 'path': filepath})
-                    continue
-            
-            # 需要更新缓存
-            md5 = compute_md5(filepath)
-            cache[filename] = (current_size, current_mtime, md5)
-            updated = True
-            files.append({'filename': filename, 'md5': md5, 'path': filepath})
-            
-        except Exception as e:
-            print(f"Error processing {filename}: {str(e)}")
-    
+
+    # 递归遍历所有子目录
+    for root, dirs, filenames in os.walk(VIDEO_DIR,followlinks=True):
+        for filename in filenames:
+            # 过滤非视频文件
+            ext = filename.split('.')[-1].lower()
+            if ext not in ['mp4', 'avi', 'mov', 'mkv', 'aac', 'mp3', 'flac']:
+                continue
+
+            filepath = os.path.join(root, filename)
+            try:
+                stat = os.stat(filepath)
+                current_size = stat.st_size
+                current_mtime = stat.st_mtime
+
+                # 使用相对路径作为缓存键(可选)
+                rel_path = os.path.relpath(filepath, VIDEO_DIR)
+                
+                # 检查缓存有效性
+                if rel_path in cache:
+                    cached_size, cached_mtime, cached_md5 = cache[rel_path]
+                    if cached_size == current_size and cached_mtime == current_mtime:
+                        files.append({'filename': filename, 'md5': cached_md5, 'path': filepath})
+                        continue
+
+                # 需要更新缓存
+                md5 = compute_md5(filepath)
+                cache[rel_path] = (current_size, current_mtime, md5)
+                updated = True
+                files.append({'filename': filename, 'md5': md5, 'path': filepath})
+
+            except Exception as e:
+                print(f"Error processing {filepath}: {str(e)}")
+
     # 保存更新后的缓存
     if updated:
         save_md5_cache(cache)
-    
+
     return files
 
 def load_weights():