有时候音箱或汽车TF卡和SD卡的音乐音频播放顺序错误,使用这个按名称统一排序后即可正常播放

来源:原创 发布时间:2025-03-31 20:01:43 作者:步里 阅读量:43

import os
import re
import hashlib
from datetime import datetime, timedelta
import pywintypes
import win32file
import win32con

# 预编译正则表达式提升自然排序性能
NATURAL_SORT_RE = re.compile(r'(\d+)')

# 第一步:优化文件名处理(仅处理扩展名)
def sanitize_filename(filename):
    base, ext = os.path.splitext(filename)
    # 仅处理扩展名,保留原始名称中的空格
    if ext.lower() != '.mp3':
        ext = '.mp3'
    # 限制文件名长度防止溢出(取消下划线填充)
    return f"{base[:50]}{ext}"  # 最大总长度54字符(50+4)

# 第二步:单次遍历目录(减少IO开销)
mp3_files = []
renamed_log = []
print("? 扫描中...", end='', flush=True)

# 单次遍历同时筛选和计数
for filename in os.listdir():
    if filename.lower().endswith('.mp3'):
        mp3_files.append(filename)
total_files = len(mp3_files)
print(f"共发现 {total_files} 个MP3文件")

# 自然排序算法
def natural_sort_key(s):
    return [int(text) if text.isdigit() else text.lower()
            for text in NATURAL_SORT_RE.split(s)]

mp3_files.sort(key=natural_sort_key)

# 第三步:批量处理重命名(安全冲突处理)
processed = 0
for idx in range(len(mp3_files)-1, -1, -1):  # 逆向遍历避免冲突
    filename = mp3_files[idx]
    clean_name = sanitize_filename(filename)
    
    if clean_name != filename:
        base, ext = os.path.splitext(clean_name)
        # 使用更安全的哈希处理冲突
        unique_id = hashlib.md5(filename.encode()).hexdigest()[:8]
        temp_name = f"{base}_{unique_id}{ext}"
        
        try:
            os.rename(filename, temp_name)
            renamed_log.append((filename, temp_name))
            mp3_files[idx] = temp_name
        except Exception as e:
            mp3_files.pop(idx)  # 移除无法处理项
            print(f"\n⚠️ 改名失败:{filename} → {temp_name} - {str(e)}")
    
    processed += 1
    if processed % 10 == 0:  # 降低进度刷新频率
        print(f"\r? 扫描中... {processed}/{total_files}", end='', flush=True)

print("\n\n? 扫描完成,开始时间设置...")

# 第四步:预计算时间序列
start_dt = datetime.now() - timedelta(minutes=1)
time_sequence = [start_dt + timedelta(seconds=i*2) for i in range(len(mp3_files))]

# 第五步:安全设置文件时间
success_count = 0
for idx, (filename, target_dt) in enumerate(zip(mp3_files, time_sequence)):
    file_path = os.path.abspath(filename)
    
    try:
        # 创建时间对象
        py_time = pywintypes.Time(target_dt)
        timestamp = target_dt.timestamp()
        
        # 显式文件句柄管理
        h_file = win32file.CreateFile(
            file_path,
            win32con.GENERIC_WRITE,
            win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
            None,
            win32con.OPEN_EXISTING,
            win32con.FILE_ATTRIBUTE_NORMAL,
            None
        )
        
        # 设置时间并立即关闭
        win32file.SetFileTime(h_file, py_time, py_time, py_time)
        h_file.Close()
        
        # 同步Unix时间戳
        os.utime(file_path, (timestamp, timestamp))
        success_count += 1
        
        if idx % 10 == 0:  # 降低进度刷新频率
            print(f"\r✅ 已处理 {idx+1}/{len(mp3_files)}", end='', flush=True)
            
    except Exception as e:
        print(f"\n? 失败({idx+1}): {filename} - {str(e)}")
    finally:
        # 确保句柄关闭
        if 'h_file' in locals():
            try: h_file.Close()
            except: pass

# 结果输出(保持原样)
print(f"\n\n? 操作完成!共处理{len(mp3_files)}个文件")
print(f"  ✅ 成功:{success_count}个  |  ❌ 失败:{len(mp3_files)-success_count}个")
if renamed_log:
    print("\n? 文件名优化示例:")
    print(f"  原文件名 → 新文件名(前3条)")
    for old, new in renamed_log[:3]:
        print(f"  {old} → {new}")
    if len(renamed_log) > 3:
        print(f"  ...(共{len(renamed_log)}条,完整记录见同目录rename.log)")
        with open('rename.log', 'w', encoding='utf-8') as f:
            f.write('\n'.join([f"{old} → {new}" for old, new in renamed_log]))

print("\n? 三重验证方法:")
print("  1. 资源管理器地址栏输入:?sort=name  → 应与时间排序一致")
print("  2. 按住Shift右键→属性:创建/修改时间均为设定值(精确到秒)")
print("  3. 播放测试:车载/音箱按时间排序应与文件名顺序完全一致")
print("\n? 提示:若处理超500个文件,建议将time_step调至5秒以上")

我要评论

网友评论


步里

评论时间:2025-04-03 19:35:10

import os
import re
import hashlib
from datetime import datetime, timedelta
import pywintypes
import win32file
import win32con
import eyed3  # 需要安装:pip install eyed3

# 预编译正则表达式提升自然排序性能
NATURAL_SORT_RE = re.compile(r'(\d+)')

# 第一步:优化文件名处理(仅处理扩展名)
def sanitize_filename(filename):
    base, ext = os.path.splitext(filename)
    # 仅处理扩展名,保留原始名称中的空格
    if ext.lower() != '.mp3':
        ext = '.mp3'
    # 限制文件名长度防止溢出(取消下划线填充)
    return f"{base[:50]}{ext}"  # 最大总长度54字符(50+4)

# 第二步:单次遍历目录(减少IO开销)
mp3_files = []
renamed_log = []
print("? 扫描中...", end='', flush=True)

# 单次遍历同时筛选和计数
for filename in os.listdir():
    if filename.lower().endswith('.mp3'):
        mp3_files.append(filename)
total_files = len(mp3_files)
print(f"共发现 {total_files} 个MP3文件")

# 自然排序算法
def natural_sort_key(s):
    return [int(text) if text.isdigit() else text.lower()
            for text in NATURAL_SORT_RE.split(s)]

mp3_files.sort(key=natural_sort_key)

# 第三步:批量处理重命名(安全冲突处理)
processed = 0
for idx in range(len(mp3_files)-1, -1, -1):  # 逆向遍历避免冲突
    filename = mp3_files[idx]
    clean_name = sanitize_filename(filename)
    
    if clean_name != filename:
        base, ext = os.path.splitext(clean_name)
        # 使用更安全的哈希处理冲突
        unique_id = hashlib.md5(filename.encode()).hexdigest()[:8]
        temp_name = f"{base}_{unique_id}{ext}"
        
        try:
            os.rename(filename, temp_name)
            renamed_log.append((filename, temp_name))
            mp3_files[idx] = temp_name
        except Exception as e:
            mp3_files.pop(idx)  # 移除无法处理项
            print(f"\n⚠️ 改名失败:{filename} → {temp_name} - {str(e)}")
    
    processed += 1
    if processed % 10 == 0:  # 降低进度刷新频率
        print(f"\r? 扫描中... {processed}/{total_files}", end='', flush=True)

print("\n\n? 扫描完成,开始时间设置...")

# 第四步:预计算时间序列
start_dt = datetime.now() - timedelta(minutes=1)
time_sequence = [start_dt + timedelta(seconds=i*2) for i in range(len(mp3_files))]

# 第五步:安全设置文件时间并更新ID3标签
success_count = 0
for idx, (filename, target_dt) in enumerate(zip(mp3_files, time_sequence)):
    file_path = os.path.abspath(filename)
    
    try:
        # 创建时间对象
        py_time = pywintypes.Time(target_dt)
        timestamp = target_dt.timestamp()
        
        # 显式文件句柄管理
        h_file = win32file.CreateFile(
            file_path,
            win32con.GENERIC_WRITE,
            win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
            None,
            win32con.OPEN_EXISTING,
            win32con.FILE_ATTRIBUTE_NORMAL,
            None
        )
        
        # 设置时间并立即关闭
        win32file.SetFileTime(h_file, py_time, py_time, py_time)
        h_file.Close()
        
        # 同步Unix时间戳
        os.utime(file_path, (timestamp, timestamp))
        
        # 自动修复损坏的ID3标签并更新Track Number字段
        audiofile = eyed3.load(file_path)
        if audiofile.tag is None:
            audiofile.initTag()
        audiofile.tag.track_num = (idx + 1, len(mp3_files))
        audiofile.tag.save()
        
        success_count += 1
        
        if idx % 10 == 0:  # 降低进度刷新频率
            print(f"\r✅ 已处理 {idx+1}/{len(mp3_files)}", end='', flush=True)
            
    except Exception as e:
        print(f"\n? 失败({idx+1}): {filename} - {str(e)}")
    finally:
        # 确保句柄关闭
        if 'h_file' in locals():
            try: h_file.Close()
            except: pass

# 结果输出(保持原样)
print(f"\n\n? 操作完成!共处理{len(mp3_files)}个文件")
print(f"  ✅ 成功:{success_count}个  |  ❌ 失败:{len(mp3_files)-success_count}个")
if renamed_log:
    print("\n? 文件名优化示例:")
    print(f"  原文件名 → 新文件名(前3条)")
    for old, new in renamed_log[:3]:
        print(f"  {old} → {new}")
    if len(renamed_log) > 3:
        print(f"  ...(共{len(renamed_log)}条,完整记录见同目录rename.log)")
        with open('rename.log', 'w', encoding='utf-8') as f:
            f.write('\n'.join([f"{old} → {new}" for old, new in renamed_log]))

print("\n? 三重验证方法:")
print("  1. 资源管理器地址栏输入:?sort=name  → 应与时间排序一致")
print("  2. 按住Shift右键→属性:创建/修改时间均为设定值(精确到秒)")
print("  3. 播放测试:车载/音箱按时间排序应与文件名顺序完全一致")
print("\n? 提示:若处理超500个文件,建议将time_step调至5秒以上")

  文章归档

步里软件开发服务部    我要留言
苏ICP备2025160072号-1
Catfish(鲶鱼) Blog V 4.0.0