#!/usr/bin/env python3 """ 导入 Mixkit BGM 音频文件到数据库并上传七牛云 扫描 mixkit_bgm/ 目录下的分类文件夹,读取音频元数据并插入 mjk_bgm_musics 表 同时上传音频到七牛云视频/音频 bucket,保存 URL。 """ import asyncio import os import sys from pathlib import Path # 将项目根目录加入 Python 路径 project_root = Path(__file__).parent.parent sys.path.insert(0, str(project_root)) # 加载环境变量 from dotenv import load_dotenv load_dotenv() from mutagen.mp3 import MP3 from sqlalchemy import select from app.db.session import AsyncSessionLocal from app.models.bgm_music import BgmMusic from app.services.qiniu_service import get_qiniu_service BGM_BASE_DIR = Path("/Users/0fun/work/meijiaka-zy/mixkit_bgm") def parse_title(filename: str) -> str: """从文件名解析标题,如 '105_See_Line_Funk.mp3' -> 'See Line Funk'""" # 去掉扩展名 name = filename.rsplit(".", 1)[0] # 去掉开头的编号前缀(如 105_) parts = name.split("_", 1) if len(parts) > 1 and parts[0].isdigit(): title_part = parts[1] else: title_part = name # 将下划线替换为空格 return title_part.replace("_", " ") def get_duration(filepath: Path) -> float | None: """获取音频文件时长(秒)""" try: audio = MP3(str(filepath)) return audio.info.length except Exception as e: print(f" 无法读取时长: {filepath.name} ({e})") return None async def import_bgm(): """扫描目录并导入数据库,同时上传七牛云""" if not BGM_BASE_DIR.exists(): print(f"错误: BGM 目录不存在: {BGM_BASE_DIR}") return categories = [d.name for d in BGM_BASE_DIR.iterdir() if d.is_dir()] print(f"发现分类: {categories}") # 初始化七牛云服务 try: qiniu = get_qiniu_service() print("七牛云服务初始化成功") except ValueError as e: print(f"七牛云配置错误: {e}") return async with AsyncSessionLocal() as session: # 清空现有数据(可选) result = await session.execute(select(BgmMusic)) existing = result.scalars().all() if existing: print(f"数据库中已有 {len(existing)} 条 BGM 记录,将删除后重新导入") for row in existing: await session.delete(row) await session.commit() total = 0 upload_ok = 0 upload_fail = 0 for category in sorted(categories): cat_dir = BGM_BASE_DIR / category files = sorted([f for f in cat_dir.iterdir() if f.suffix.lower() in (".mp3", ".wav", ".m4a")]) print(f"\n分类 [{category}]: {len(files)} 首") for idx, filepath in enumerate(files): title = parse_title(filepath.name) relative_path = f"{category}/{filepath.name}" duration = get_duration(filepath) # 上传七牛云 qiniu_key = f"meijiaka-zy/bgm/{relative_path}" url = None try: upload_result = qiniu.upload_file( local_path=str(filepath), key=qiniu_key, file_type="audio", check_duplicate=True, ) url = upload_result.get("url") if upload_result.get("isDuplicate"): print(f" + {title} (复用已有文件)") else: print(f" + {title} (上传成功)") upload_ok += 1 except Exception as e: print(f" ! {title} (上传失败: {e})") upload_fail += 1 # 上传失败也继续入库,只是 url 为空 bgm = BgmMusic( title=title, artist=None, category=category, file_path=relative_path, url=url, duration=duration, status="active", sort_order=idx, ) session.add(bgm) total += 1 await session.commit() print(f"\n导入完成,共 {total} 首") print(f" 上传成功: {upload_ok} 首") print(f" 上传失败: {upload_fail} 首") if __name__ == "__main__": asyncio.run(import_bgm())