自动翻译播放器源码
# -*- coding:utf-8 -*-
from PyQt5.Qt import pyqtSignal,QApplication,QFileDialog,QMutex,QSlider
from PyQt5.uic import loadUi
from PyQt5.QtCore import pyqtSignal,QObject,QTimer,QThread
from PyQt5.QtGui import QIcon,QPixmap,QColor
from pysubs2 import SSAFile, SSAEvent, make_time
import win32com.client as wincl
import os, platform,threading,sys,time,wave,re , pythoncom , glob
# 设置VLC库路径,需在import vlc之前
if len(sys.argv) > 1:
os.chdir((sys.argv[0]).replace((sys.argv[0].split('\\'))[-1] , ''))
os.add_dll_directory(os.getcwd())
import vlc
ERROR = ''
qmut_1 = QMutex() # 创建线程锁
class Sound(QThread): # 线程1
def __init__(self,text):
self.text = text
super().__init__()
def run(self):
qmut_1.lock() # 加锁
pythoncom.CoInitialize()
(wincl.Dispatch("SAPI.SpVoice")).Speak(self.text)
pythoncom.CoUninitialize()
qmut_1.unlock() # 解锁.
class Player:
'''
args:设置 options
'''
def __init__(self, *args):
def startplay():
if args:
instance = vlc.Instance(*args)
self.media = instance.media_player_new()
else:
self.media = vlc.MediaPlayer()
thread = threading.Thread(target=startplay())
thread.start()
# 设置待播放的url地址或本地文件路径,每次调用都会重新加载资源
def set_uri(self, uri):
self.media.set_mrl(uri)
# 播放 成功返回0,失败返回-1
def play(self, path=None):
if path:
self.set_uri(path)
return self.media.play()
else:
return self.media.play()
# 暂停
def pause(self):
self.media.pause()
# 恢复
def resume(self):
self.media.set_pause(0)
# 停止
def stop(self):
self.media.stop()
# 释放资源
def release(self):
return self.media.release()
# 是否正在播放
def is_playing(self):
return self.media.is_playing()
# 已播放时间,返回毫秒值
def get_time(self):
return self.media.get_time()
# 拖动指定的毫秒值处播放。成功返回0,失败返回-1 (需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
def set_time(self, ms):
return self.media.set_time(ms)
# 音视频总长度,返回毫秒值
def get_length(self):
return self.media.get_length()
# 获取当前音量(0~100)
def get_volume(self):
return self.media.audio_get_volume()
# 设置音量(0~100)
def set_volume(self, volume):
return self.media.audio_set_volume(volume)
# 返回当前状态:正在播放;暂停中;其他
def get_state(self):
state = self.media.get_state()
if state == vlc.State.Playing:
return 1
elif state == vlc.State.Paused:
return 0
else:
return -1
# 当前播放进度情况。返回0.0~1.0之间的浮点数
def get_position(self):
return self.media.get_position()
# 拖动当前进度,传入0.0~1.0之间的浮点数(需要注意,只有当前多媒体格式或流媒体协议支持才会生效)
def set_position(self, float_val):
return self.media.set_position(float_val)
# 获取当前文件播放速率
def get_rate(self):
return self.media.get_rate()
# 设置播放速率(如:1.2,表示加速1.2倍播放)
def set_rate(self, rate):
return self.media.set_rate(rate)
# 设置宽高比率(如"16:9","4:3")
def set_ratio(self, ratio):
self.media.video_set_scale(0) # 必须设置为0,否则无法修改屏幕宽高
self.media.video_set_aspect_ratio(ratio)
# 设置窗口句柄
def set_window(self, wm_id):
if platform.system() == 'Windows':
self.media.set_hwnd(wm_id)
else:
self.media.set_xwindow(wm_id)
# 注册监听器
def add_callback(self, event_type, callback):
self.media.event_manager().event_attach(event_type, callback)
print('这里是监听器')
Stats().ui.videotime.setMaximum(self.media.get_length())
Stats().ui.videotime.setValue(self.media.get_time())
# 移除监听器
def remove_callback(self, event_type, callback):
self.media.event_manager().event_detach(event_type, callback)
class Stats:
def __init__(self):
# 从文件中加载UI定义 从 UI 定义中动态 创建一个相应的窗口对象 注意:里面的控件对象也成为窗口对象的属性了 比如 self.ui.button , self.ui.textEdit
self.ui = loadUi('plugins\\UI\\main.ui')
self.ui.setWindowIcon(QIcon('plugins\\UI\\logo.png'))
self.path = ''
self.loging = ''
self.Enable = True
self.player = Player()
self.player.set_window(self.ui.frame.winId())
self.tw = timework()
self.tw.videotime.connect(self.videotime)
self.ui.answer.setText('朗读已启用')
self.ui.cmd.returnPressed.connect(self.playButton)
self.ui.openButton.clicked.connect(self.openFileDialog) #打开
self.ui.backButton.clicked.connect(self.backButton) #后退
self.ui.playButton.clicked.connect(self.playButton) #播放/暂停
self.ui.flowordButton.clicked.connect(self.flowordButton) #前进
# self.ui.stopButton.setIcon(QIcon('UI\stop.png')) #停止
self.ui.stopButton.clicked.connect(self.stopButton) #停止
self.ui.sound.valueChanged.connect(self.sound) #声音
self.ui.videotime.sliderMoved.connect(self.videotime) #拖动进度条同步刷新画面
# self.ui.videotime.sliderReleased.connect(self.videotime) #拖动进度条完毕刷新界面
self.ui.frame.setStyleSheet("background-color: rgb(0, 0, 0);")#设置播放控件背景色
self.ui.answer.clicked.connect(self.victostr) # 回答问题
self.clock_time = 0
self.timer = QTimer() # 生成定时器
self.timer.start(200)
self.File = sys.argv
self.timetime = 0
self.skip = 0
self.timer.timeout.connect(self.clock) # 绑定计时函数 self.clock
def clock(self):
num = self.player.get_time() #获取播放进度
if num < 0 :
num = 0
if num > 0:
self.ui.videotime.setValue(num) #同步进度条
self.ui.minlcd.display(str(num//60000+100)[1:]) #显示分钟数
self.ui.slcd.display(':' + str(num//1000%60+100)[1:]) #显示秒数
self.playsubs(num)
def playsubs(self , num):
for i in self.subs:
if (i.start) <= num <= (i.end):
sub = i.text.replace(r'\N' , '\n')
# if not self.is_chinese(sub):
# sub = self.translate(sub)
if '\n' in sub:
sub = sub.split('\n')[0]
if self.Enable and self.loging != sub:
print(f'进度:{str(num)} 开始时间:{str(i.start)} 结束时间:{str(i.end)} 字幕:{sub}')
self.ui.echoanswer.setText(sub)
self.loging = sub
self.thread_1 = Sound(sub) # 创建线程
self.thread_1.start() # 开始线程
def victostr(self):
if self.Enable:
self.ui.answer.setText('朗读已禁用')
self.Enable = False
self.ui.echoanswer.setText('')
else:
self.ui.answer.setText('朗读已启用')
self.Enable = True
def backButton(self): #后退
self.player.set_time(self.player.get_time() - 5000)
self.ui.videotime.setValue(self.player.get_time())
def playButton(self): #播放/暂停
if self.path:
if self.player.is_playing() == 1 :
self.player.pause()
self.ui.playButton.setText('播放')
else:
self.player.resume()
self.ui.playButton.setText('暂停')
self.ui.videotime.setValue(self.player.get_time())
else:
self.openFileDialog()
def flowordButton(self): #前进
self.player.set_time(self.player.get_time() +5000)
self.ui.videotime.setValue(self.player.get_time())
def stopButton(self): #停止ian
self.player.stop()
self.ui.videotime.setValue(self.player.get_time())
def sound(self):
self.player.set_volume(self.ui.sound.value())
def videotime(self):
self.ui.cmd.setText('')
self.player.set_time(self.ui.videotime.value())
def initialization(self): #初始化,等待接收文件
pass
def openFile(self):#类型关联打开文件
self.getsubs(self.File[1])
def timehandle(self,timestr):
if ':' in timestr:
stoptime =timestr.split(':')
second = float((stoptime)[0]) * 60 + float((stoptime)[1]) # 获得暂停时间
else:
second = float(timestr)
return second
def openFileDialog(self):#打开文件
# 生成文件对话框对象
dialog = QFileDialog()
# 设置文件过滤器,这里是任何文件,包括目录噢
dialog.setFileMode(QFileDialog.AnyFile)
# 设置显示文件的模式,这里是详细模式
dialog.setViewMode(QFileDialog.Detail)
if dialog.exec_():
fileNames = dialog.selectedFiles()
self.getsubs(fileNames[0])
def getsubs(self , path = ''):
self.path = path
self.ui.setWindowTitle(path)#将路径显示到标题栏上
self.player.play(path)
self.ui.playButton.setText('暂停')
time.sleep(0.1)
self.ui.sound.setValue(self.player.get_volume())
self.ui.videotime.setMaximum(self.player.get_length())
self.ui.videotime.setValue(self.player.get_time())
P = os.path.dirname(path)
if subpath := glob.glob(f'{P}/*.srt'):
self.subs = SSAFile.load(subpath[0])
elif subpath := glob.glob(f'{P}/*.ass'):
self.subs = SSAFile.load(subpath[0])
elif subpath := glob.glob(f'{P}/*.ssa'):
self.subs = SSAFile.load(subpath[0])
class timework(QObject):
videotime = pyqtSignal(QSlider,int)
app = QApplication([])
stats = Stats()
stats.ui.show()
stats.initialization()
sys.exit(app.exec_())