[Python] 纯文本查看 复制代码
# -*- coding=utf-8
import logging
import subprocess
from re import sub, search
import pyperclip, sys
import os
import send2trash
# 配置日志
logging.basicConfig(filename='error_log.txt', filemode='a', format='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S', level=logging.ERROR)
def is_video(filename: str, skip=False) -> bool:
"""
判断文件是否为视频文件
如果是H264、vp8、mpeg2编码器的视频文件就返回True
:param filename:
:return:
"""
try:
cmd = subprocess.run(
rf'ffprobe -show_streams "{filename}"',
shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding='utf-8')
if skip:
# 跳过特定的动图格式
unalloyed_bool = any(filename.lower().endswith(suffix) for suffix in ['.swf', '.apng', '.gif'])
# 跳过已压缩的某些编码器
if search('\ncodec_name=(av1|hevc|vp9)\n', cmd.stdout) or unalloyed_bool:
return False
# 跳过字幕文件格式
unalloyed_bool = any(filename.lower().endswith(suffix) for suffix in ['.srt', '.ass', '.ssa','.vtt','.lrc','.cc','.utf','.txt','.qly','.ksc','.a16'])
if unalloyed_bool:
return False
# 判断依据是视频流信息是否包含视频文件的时长
video_search = search('\nduration=(\\d+\\.\\d+)', cmd.stdout)
# 判断依据是视频文件的后缀名,一些动图或swf不压缩
if video_search:
# 视频长度至少0.1秒,说明是视频文件
if float(video_search.group(1)) > 0.1:
return True
if search('\ncodec_name=(vp8|vp9)\n', cmd.stdout):
# vp8没有duration信息,但可以判断是否为视频文件
return True
logging.info(f'{filename}是未知的编码器')
return False
except:
# 报错,说明文件不是视频文件
return False
def rename_files(directory):
"""
重命名目录下所有视频文件,文件名格式为:文件夹名_文件名
:param directory:
:return:
"""
# 遍历目录下的所有文件夹
for foldername, subfolders, filenames in os.walk(directory):
for filename in filenames:
# 跳过非视频文件
old_file = os.path.join(foldername, filename)
if is_video(old_file):
# 构建新的文件名
new_filename = filename
# print(new_filename)
new_str=''# 注释掉,是去重
for name in foldername.split(os.sep)[:directory.split(os.sep).__len__() - 1:-1]:
# 命名新文件名,从最深层文件夹名到最浅层文件夹名都加上
if not new_filename.startswith(name):
new_filename = name + '_' + new_filename
new_str = name + '_' + new_str# 注释掉,是去重
# print(new_str)
# print(not filename.startswith(new_str))
# 构建原文件和新的完整路径
if not filename.startswith(new_str):
new_file = os.path.join(foldername, new_filename)
# 如果文件名已经包含文件夹名,则跳过
# 重命名文件
os.rename(old_file, new_file)
# 取消重命名,把new_file换成old_file.replace(foldername.split(os.sep)[-1] + '_','')
# print(foldername.split(os.sep)[-1])
# print(filename.lower().startswith(foldername.split(os.sep)[-1]))
print(f'原文件: {old_file}\n新文件: {new_file}')
def rename_add(directory, add_str):
"""
重命名目录下所有视频文件,文件名格式为:文件夹名_文件名
:param directory:
:return:
"""
# 遍历目录下的所有文件夹
for foldername, subfolders, filenames in os.walk(directory):
for filename in filenames:
# 跳过非视频文件
old_file = os.path.join(foldername, filename)
if is_video(old_file):
# 构建新的文件名
new_filename = add_str + '_' + filename
# 构建原文件和新的完整路径
new_file = os.path.join(foldername, new_filename)
# 如果文件名已经包含文件夹名,则跳过
if not filename.startswith(add_str):
# 重命名文件
os.rename(old_file, new_file)
# 取消重命名,把new_file换成old_file.replace(foldername.split(os.sep)[-1] + '_','')
# print(foldername.split(os.sep)[-1])
# print(filename.lower().startswith(foldername.split(os.sep)[-1]))
print(f'原文件: {old_file}\n新文件: {new_file}')
def delete_files(directory):
"""
目录下如果已存在av1格式,又存在同名的MP4视频文件,则删除MP4文件到回收站
:param directory:
:return:
"""
for filename in os.listdir(directory):
if filename.lower().endswith('.av1.mp4'):
ole_file = os.path.join(directory, filename.replace('.av1.mp4', '.mp4'))
if os.path.exists(ole_file):
send2trash.send2trash(ole_file)
def video_compress(directory):
"""
对目录下所有视频文件进行压缩,使用SVT-AV1压缩
:param directory:
:return:
"""
for foldername, subfolders, filenames in os.walk(directory):
for filename in filenames:
old_file = os.path.join(foldername, filename)
if is_video(old_file, skip=True):
# 通过cmd执行命令
print(f'正在压缩 {filename}')
# 获取执行输出
try:
cmd = subprocess.run(
f'ab-av1 auto-encode -i "{old_file}" --preset 10 --svt tune=0 --svt film-grain=4 --svt film-grain-denoise=0 --pix-format yuv420p10le --max-crf 60 --min-crf 5 --min-vmaf 94',
shell=True, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True,
encoding='utf-8')
print(f'压缩完成')
send2trash.send2trash(old_file)
except subprocess.CalledProcessError as e:
# 如果命令执行出错,记录错误信息
error_msg = e.stderr
if 'Error: Failed to find a suitable crf' in error_msg:
print(f'压缩失败,原因:未能找到合适的crf')
else:
logging.error(f"{'-' * 100}\n压缩视频出错: {old_file}\n{e.stderr}\n{'-' * 100}")
print(f"压缩视频发生了错误: {old_file}")
if __name__ == '__main__':
# 给文件添加文件夹名
# rename_files(r'F:\BaiduNetdiskDownload\xianyu6')
# 给文件添加特定前缀
# rename_add(r'F:\BaiduNetdiskDownload\2D动画\Captain-Lamb_user15643288','Captain-Lamb_')
# 压缩视频
paths = [
# r'F:\BaiduNetdiskDownload\TheGRTeam',
# r'F:\BaiduNetdiskDownload\CBX-CJW',
# r'F:\BaiduNetdiskDownload\HMV ブラン 旧 秘O 5月红P合集',
# r'F:\BaiduNetdiskDownload\カズサとあけおめックス',
# r'F:\BaiduNetdiskDownload\[3D] わるいスライムの動画置場 (わるいスライムです)',
r'F:\BaiduNetdiskDownload\2D动画',
r'',
r'',
r'',
r'',
]
for path in paths:
video_compress(path)
# video_compress(r'F:\BaiduNetdiskDownload\2D动画\Hard-Degenerate\新建文件夹')
# 删除mp4原文件
# delete_files(r'F:\BaiduNetdiskDownload\20240615\超分补帧')