Commit 464b8e26 authored by smile2019's avatar smile2019

Merge remote-tracking branch 'refs/remotes/origin/feat_1' into feat_1

parents 72383c7f 7db705f9
......@@ -9,4 +9,8 @@ dist
build
log
product_test
res/ffmpeg-4.3.1/bin/output.mp4
res/ffmpeg-4.3.1/bin/qiji_local.mp4
venv/
venv37/
shenming_test
\ No newline at end of file
......@@ -78,7 +78,8 @@ def predict_long_audio_with_paddle(wav_path, pre_time, book_name, sheet_name, st
(time_stamps[i][0] + pre_time) * normal_speed)
print("插入旁白,推荐字数为%d" % recommend_lens)
# narratages.append(["", "", "", "插入旁白,推荐字数为%d" % recommend_lens])
write_to_sheet(book_name, sheet_name, ["", "", "", "插入旁白,推荐字数为%d" % recommend_lens])
# write_to_sheet(book_name, sheet_name, ["", "", "", "插入旁白,推荐字数为%d" % recommend_lens])
write_to_sheet(book_name, sheet_name, ["", "", "", "%d" % recommend_lens])
# narratages.append([round(time_stamps[i][0] + pre_time, 2), round(time_stamps[i][1] + pre_time, 2),
# text, ''])
write_to_sheet(book_name, sheet_name,
......
!
"
#
$
%
&
'
(
)
*
+
,
-
--
.
..
...
......
...................
./
.一
.数
.日
/
//
0
1
2
3
4
5
6
7
8
9
:
://
::
;
<
=
>
>>
?
@
A
Lex
[
\
]
^
_
`
exp
sub
sup
|
}
~
~~~~
·
×
×××
Δ
Ψ
γ
μ
φ
φ.
В
——
———
’‘
”,
……
…………………………………………………③
′∈
′|
∈[
∪φ∈
②c
③]
──
 
》),
〕〔
一.
一一
一下
一个
一些
一何
一切
一则
一则通过
一天
一定
一方面
一旦
一时
一来
一样
一次
一片
一番
一直
一致
一般
一起
一转眼
一边
一面
万一
三天两头
三番两次
三番五次
上下
上升
上去
上来
上述
上面
下列
下去
下来
下面
不一
不下
不久
不了
不亦乐乎
不仅
不仅...而且
不仅仅
不仅仅是
不会
不但
不但...而且
不光
不免
不再
不力
不单
不变
不只
不可
不可开交
不可抗拒
不同
不外
不外乎
不够
不大
不如
不妨
不定
不对
不少
不尽
不尽然
不巧
不已
不常
不得
不得不
不得了
不得已
不必
不怎么
不怕
不惟
不成
不拘
不择手段
不敢
不料
不断
不日
不时
不是
不曾
不止
不止一次
不比
不消
不满
不然
不然的话
不特
不独
不由得
不知不觉
不管
不管怎样
不经意
不胜
不能
不能不
不至于
不若
不要
不论
不起
不足
不过
不迭
不问
不限
与其
与其说
与否
与此同时
专门
且不说
且说
两者
严格
严重
个人
个别
中小
中间
丰富
串行
临到
为主
为了
为什么
为什麽
为何
为止
为此
为着
主张
主要
举凡
举行
乃至
乃至于
之一
之前
之后
之後
之所以
之类
乌乎
乘势
乘机
乘胜
乘虚
乘隙
也好
也就是说
也是
也罢
了解
争取
二来
二话不说
二话没说
于是
于是乎
云云
云尔
互相
交口
产生
亲口
亲手
亲眼
亲自
亲身
人人
人们
人家
人民
什么
什么样
什麽
仅仅
今后
今天
今年
今後
介于
仍旧
仍然
从不
从严
从中
从事
从今以后
从优
从古到今
从古至今
从头
从宽
从小
从新
从无到有
从早到晚
从未
从来
从此
从此以后
从而
从轻
从速
从重
他人
他们
他是
他的
代替
以上
以下
以为
以便
以免
以前
以及
以后
以外
以後
以故
以期
以来
以至
以至于
以致
任何
任凭
任务
企图
伙同
伟大
传说
传闻
似乎
似的
但凡
但愿
但是
何乐而不为
何以
何况
何处
何妨
何尝
何必
何时
何止
何苦
何须
余外
作为
你们
你是
你的
使
使得
使用
例如
依据
依照
依靠
便
便于
促进
保持
保管
保险
俺们
倍加
倍感
倒不如
倒不如说
倒是
倘使
倘或
倘然
倘若
借以
借此
假使
假如
假若
偏偏
做到
偶尔
偶而
傥然
允许
元/吨
充其极
充其量
充分
先不先
先后
先後
先生
光是
全体
全力
全年
全然
全身心
全部
全都
全面
八成
公然
共同
共总
关于
其一
其中
其二
其他
其余
其后
其它
其实
其次
具体
具体地说
具体来说
具体说来
具有
兼之
再其次
再则
再有
再次
再者
再者说
再说
决不
决定
决非
况且
准备
凑巧
凝神
几乎
几度
几时
几番
几经
凡是
凭借
出于
出去
出来
出现
分别
分头
分期
分期分批
切不可
切切
切勿
切莫
则甚
刚好
刚巧
刚才
别人
别处
别是
别的
别管
别说
到了儿
到处
到头
到头来
到底
到目前为止
前后
前此
前者
前进
前面
加上
加之
加以
加入
加强
动不动
动辄
勃然
匆匆
十分
千万
千万千万
单单
单纯
即令
即使
即便
即刻
即如
即将
即或
即是说
即若
却不
原来
又及
及其
及时
及至
双方
反之
反之亦然
反之则
反倒
反倒是
反应
反手
反映
反而
反过来
反过来说
取得
取道
受到
变成
古来
另一个
另一方面
另外
另悉
另方面
另行
只当
只怕
只是
只有
只消
只要
只限
叫做
召开
叮咚
叮当
可以
可好
可是
可能
可见
各个
各人
各位
各地
各式
各种
各级
各自
合理
同一
同时
同样
后来
后者
后面
向使
向着
否则
吧哒
呆呆地
呜呼
周围
呵呵
呼哧
呼啦
咱们
哈哈
哎呀
哎哟
哗啦
哪个
哪些
哪儿
哪天
哪年
哪怕
哪样
哪边
哪里
哼唷
唯有
啊呀
啊哈
啊哟
啪达
啷当
喔唷
嗡嗡
嘎嘎
嘎登
嘿嘿
因为
因了
因此
因着
因而
固然
在下
在于
坚决
坚持
基于
基本
基本上
处在
处处
处理
复杂
多么
多亏
多多
多多少少
多多益善
多少
多年前
多年来
多数
多次
够瞧的
大不了
大举
大事
大体
大体上
大凡
大力
大多
大多数
大大
大家
大张旗鼓
大批
大抵
大概
大略
大约
大致
大都
大量
大面儿上
失去
奋勇
她们
她是
她的
好在
好的
好象
如上
如上所述
如下
如今
如何
如其
如前所述
如同
如常
如是
如期
如果
如次
如此
如此等等
如若
始而
姑且
存在
存心
孰料
孰知
宁可
宁愿
宁肯
它们
它们的
它是
它的
安全
完全
完成
实现
实际
宣布
容易
密切
对于
对应
对待
对方
对比
将才
将要
将近
少数
尔后
尔尔
尔等
尚且
尤其
就地
就是
就是了
就是说
就此
就算
就要
尽可能
尽如人意
尽心尽力
尽心竭力
尽快
尽早
尽然
尽管
尽管如此
尽量
局外
居然
届时
属于
屡屡
屡次
屡次三番
岂但
岂止
岂非
川流不息
左右
巨大
巩固
差一点
差不多
已矣
已经
巴巴
帮助
常常
常言说
常言说得好
常言道
平素
年复一年
并不
并不是
并且
并排
并无
并没
并没有
并肩
并非
广大
广泛
应当
应用
应该
庶乎
庶几
开外
开始
开展
引起
弹指之间
强烈
强调
归根到底
归根结底
归齐
当下
当中
当儿
当前
当即
当口儿
当地
当场
当头
当庭
当时
当然
当真
当着
形成
彻夜
彻底
彼时
彼此
往往
待到
很多
很少
後来
後面
得了
得出
得到
得天独厚
得起
心里
必定
必将
必然
必要
必须
快要
忽地
忽然
怎么
怎么办
怎么样
怎奈
怎样
怎麽
急匆匆
怪不得
总之
总是
总的来看
总的来说
总的说来
总结
总而言之
恍然
恐怕
恰似
恰好
恰如
恰巧
恰恰
恰恰相反
恰逢
您们
您是
惟其
惯常
意思
愤然
愿意
慢说
成为
成年
成年累月
成心
我们
我是
我的
或则
或多或少
或是
或曰
或者
或许
战斗
截然
截至
所以
所在
所幸
所有
所谓
才能
扑通
打从
打开天窗说亮话
扩大
抑或
抽冷子
拦腰
按时
按期
按照
按理
按说
挨个
挨家挨户
挨次
挨着
挨门挨户
挨门逐户
换句话说
换言之
据实
据悉
据我所知
据此
据称
据说
掌握
接下来
接着
接著
接连不断
放量
故意
故此
故而
敞开儿
敢于
敢情
数/
整个
断然
方便
方才
方能
方面
旁人
无宁
无法
无论
既...又
既往
既是
既然
日复一日
日渐
日益
日臻
日见
时候
昂然
明显
明确
是不是
是以
是否
是的
显然
显著
普通
普遍
暗中
暗地里
暗自
更为
更加
更进一步
曾经
替代
最后
最大
最好
最後
最近
最高
有些
有关
有利
有力
有及
有所
有效
有时
有点
有的
有的是
有着
有著
朝着
末##末
本人
本地
本着
本身
权时
来不及
来得及
来看
来着
来自
来讲
来说
极为
极了
极其
极力
极大
极度
极端
构成
果然
果真
某个
某些
某某
根据
根本
格外
次第
欢迎
正值
正在
正如
正巧
正常
正是
此中
此后
此地
此处
此外
此时
此次
此间
毋宁
每个
每天
每年
每当
每时每刻
每每
每逢
比及
比如
比如说
比方
比照
比起
比较
毕竟
毫不
毫无
毫无例外
毫无保留地
沙沙
没奈何
没有
沿
沿着
注意
深入
清楚
满足
漫说
然则
然后
然後
然而
照着
牢牢
特别是
特殊
特点
犹且
犹自
独自
猛然
猛然间
率尔
率然
现代
现在
理应
理当
理该
瑟瑟
甚且
甚么
甚或
甚而
甚至
甚至于
用来
由于
由是
由此
由此可见
略为
略加
略微
白白
的确
的话
皆可
目前
直到
直接
相似
相信
相反
相同
相对
相对而言
相应
相当
相等
省得
看上去
看出
看到
看来
看样子
看看
看见
看起来
真是
真正
眨眼
着呢
矣乎
矣哉
知道
确定
碰巧
社会主义
积极
移动
究竟
穷年累月
突出
突然
立刻
立即
立地
立时
立马
竟然
竟而
第二
等到
等等
策略地
简直
简而言之
简言之
类如
精光
紧接着
累年
累次
纯粹
纵令
纵使
纵然
练习
组成
经常
经过
结合
结果
绝不
绝对
绝非
绝顶
继之
继后
继续
继而
维持
综上所述
缕缕
罢了
老大
老是
老老实实
考虑
而且
而况
而又
而后
而外
而已
而是
而言
而论
联系
联袂
背地里
背靠背
能否
能够
自个儿
自从
自各儿
自后
自家
自己
自打
自身
至于
至今
至若
般的
良好
若夫
若是
若果
若非
范围
莫不
莫不然
莫如
莫若
莫非
获得
藉以
虽则
虽然
虽说
行为
行动
表明
表示
要不
要不是
要不然
要么
要是
要求
规定
觉得
譬喻
譬如
认为
认真
认识
许多
论说
设使
设或
设若
诚如
诚然
话说
该当
说明
说来
说说
请勿
诸位
诸如
谁人
谁料
谁知
豁然
贼死
赖以
赶快
赶早不赶晚
起先
起初
起头
起来
起见
起首
趁便
趁势
趁早
趁机
趁热
趁着
越是
路经
转动
转变
转贴
轰然
较为
较之
较比
达到
达旦
迅速
过于
过去
过来
运用
近几年来
近年来
近来
还是
还有
还要
这一来
这个
这么
这么些
这么样
这么点儿
这些
这会儿
这儿
这就是说
这时
这样
这次
这点
这种
这般
这边
这里
这麽
进入
进去
进来
进步
进而
进行
连同
连声
连日
连日来
连袂
连连
迟早
迫于
适应
适当
适用
逐步
逐渐
通常
通过
造成
遇到
遭到
遵循
遵照
避免
那个
那么
那么些
那么样
那些
那会儿
那儿
那时
那末
那样
那般
那边
那里
那麽
部分
鄙人
采取
里面
重大
重新
重要
鉴于
针对
长期以来
长此下去
长线
长话短说
问题
间或
防止
附近
陈年
限制
陡然
除了
除却
除去
除外
除开
除此
除此之外
除此以外
除此而外
除非
随后
随时
随着
随著
隔夜
隔日
难得
难怪
难说
难道
难道说
集中
需要
非但
非常
非徒
非得
非特
非独
顶多
顷刻
顷刻之间
顷刻间
顺着
顿时
风雨无阻
首先
马上
高低
高兴
默然
默默地
︿
)÷(1-
)、
+ξ
++
,也
-β
--
-[*]-
0:2
1.
12%
2.3%
5:0
<±
<Δ
<λ
<φ
<<
=″
=☆
=(
=-
=[
={
>λ
LI
R.L.
ZXFITL
[①①]
[①②]
[①③]
[①④]
[①⑤]
[①⑥]
[①⑦]
[①⑧]
[①⑨]
[①A]
[①B]
[①C]
[①D]
[①E]
[①]
[①a]
[①c]
[①d]
[①e]
[①f]
[①g]
[①h]
[①i]
[①o]
[②
[②①]
[②②]
[②③]
[②④
[②⑤]
[②⑥]
[②⑦]
[②⑧]
[②⑩]
[②B]
[②G]
[②]
[②a]
[②b]
[②c]
[②d]
[②e]
[②f]
[②g]
[②h]
[②i]
[②j]
[③①]
[③⑩]
[③F]
[③]
[③a]
[③b]
[③c]
[③d]
[③e]
[③g]
[③h]
[④]
[④a]
[④b]
[④c]
[④d]
[④e]
[⑤]
[⑤]]
[⑤a]
[⑤b]
[⑤d]
[⑤e]
[⑤f]
[⑥]
[⑦]
[⑧]
[⑨]
[⑩]
[*]
[-
[]
]∧′=[
][
_
a]
b]
c]
e]
f]
ng昉
{-
}>
~±
~+
......@@ -16,14 +16,23 @@ from prompt_dialog import Prompt_Dialog
class Create_Dialog(QDialog, Ui_Dialog):
init_project_signal = pyqtSignal(str)
def __init__(self):
def __init__(self, mainWindow):
super(Create_Dialog, self).__init__()
self.mainWindow = mainWindow
self.setupUi(self)
self.setWindowTitle("新建工程")
self.get_dir.clicked.connect(self.choose_root)
self.confirm.clicked.connect(self.create_project)
self.get_video_dir.clicked.connect(self.choose_video)
self.prompt_dialog = Prompt_Dialog()
self.cancel.clicked.connect(self.close_dialog)
self.video_path = None
def choose_video(self):
path = QFileDialog.getOpenFileUrl(self, "选择待导入视频", QUrl(
os.getcwd()), "Video Files(*.mp4 *.rmvb *mkv *avi *.);; 所有文件(*.*)")[0]
self.video_input.setText(path.path()[1:])
self.video_path = path
def choose_root(self):
"""选择存放新工程的文件夹
......@@ -54,6 +63,7 @@ class Create_Dialog(QDialog, Ui_Dialog):
self.prompt_dialog.show_with_msg("请输入工程名称")
else:
self.prompt_dialog.show_with_msg("请输入合法文件夹路径")
self.mainWindow.play_video(self.video_path)
def close_dialog(self):
"""关闭窗口
......
......@@ -29,6 +29,13 @@ class Ui_Dialog(object):
self.get_dir.setObjectName("get_dir")
self.gridLayout.addWidget(self.get_dir, 0, 2, 1, 1)
self.video_input = QtWidgets.QLineEdit(Dialog)
self.video_input.setObjectName("video_input")
self.gridLayout.addWidget(self.video_input, 2, 1, 1, 1)
self.get_video_dir = QtWidgets.QPushButton(Dialog)
self.get_video_dir.setObjectName("get_video_dir")
self.gridLayout.addWidget(self.get_video_dir, 2, 2, 1, 1)
self.rootLabel = QtWidgets.QLabel(Dialog)
self.rootLabel.setObjectName("rootLabel")
self.gridLayout.addWidget(self.rootLabel, 0, 0, 1, 1)
......@@ -37,6 +44,10 @@ class Ui_Dialog(object):
self.nameLabel.setObjectName("nameLabel")
self.gridLayout.addWidget(self.nameLabel, 1, 0, 1, 1)
self.videoPath = QtWidgets.QLabel(Dialog)
self.videoPath.setObjectName("videoPath")
self.gridLayout.addWidget(self.videoPath, 2, 0, 1, 1)
self.gridLayout.addWidget(self.name_input, 1, 1, 1, 1)
self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
self.horizontalLayout = QtWidgets.QHBoxLayout()
......@@ -68,6 +79,8 @@ class Ui_Dialog(object):
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.nameLabel.setText(_translate("Dialog", "工程名称"))
self.rootLabel.setText(_translate("Dialog", "目标路径"))
self.videoPath.setText(_translate("Dialog", "视频路径"))
self.get_dir.setText(_translate("Dialog", "打开文件夹"))
self.get_video_dir.setText(_translate("Dialog", "导入视频"))
self.confirm.setText(_translate("Dialog", "确认"))
self.cancel.setText(_translate("Dialog", "取消"))
@echo on
%1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close) && exit
@REM @echo on
@REM %1 mshta vbscript:CreateObject("Shell.Application").ShellExecute("cmd.exe","/c %~s0 ::","","runas",1)(window.close) && exit
cd /d %~dp0
IF EXIST "%PROGRAMFILES(X86)%" (GOTO 64BIT) ELSE (GOTO 32BIT)
......@@ -16,6 +16,7 @@ GOTO END
:END
c:
cd C:\LavFilters\
call install_audio.bat
call install_splitter.bat
......
......@@ -98,7 +98,7 @@ def detect_with_asr(video_path: str, book_path: str, start_time=0, end_time=-1,
os.remove(book_path)
book_name_xlsx = book_path
sheet_name_xlsx = "旁白插入位置建议"
table_head = [["起始时间", "终止时间", "字幕", '建议', '解说脚本']]
table_head = [["起始时间", "终止时间", "字幕", '建议旁白字数', '解说脚本']]
create_sheet(book_name_xlsx, sheet_name_xlsx, table_head)
sys.path.append("PaddlePaddle_DeepSpeech2")
......
......@@ -27,7 +27,7 @@ import difflib
import re
from typing import Tuple, Union
from utils import reverse_time_to_seconds
from detect_with_asr import create_sheet, write_to_sheet
from main_window import MainWindow, Element
......@@ -93,6 +93,7 @@ def get_position(video_path: str, start_time: float, rate: float, rate_bottom: f
Returns:
Tuple[float, float]: 字幕在整个画面中的上下边界位置
"""
print(">>>>>>>>>>open")
print("video_path:", video_path)
video = cv2.VideoCapture(video_path)
# print("video:", video)
......@@ -104,7 +105,6 @@ def get_position(video_path: str, start_time: float, rate: float, rate_bottom: f
pre_txt = None
video.set(cv2.CAP_PROP_POS_FRAMES, start)
# height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT) * 0.6)
print(">>>>>>>>>>>>video height")
print(cv2.CAP_PROP_FRAME_HEIGHT)
print(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
up = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT) * (rate))
......@@ -249,7 +249,6 @@ def detect_subtitle(img: np.ndarray) -> Tuple[Union[str, None], float]:
img = img[int(up_b - height*0.7):int(down_b + height*0.7)]
# 针对低帧率的视频做图像放大处理
print(">>>>>>>>>>>>>>>>>>>>>img shape")
print(height)
print(up_b)
print(down_b)
......@@ -355,7 +354,8 @@ def process_video(video_path: str, begin: float, end: float, book_path: str, she
print('--------------------------------------------------')
recommend_lens = int((cur_time - end_time) * normal_speed)
# write_to_sheet(book_path, sheet_name, ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
# add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '%d' % recommend_lens])
# 判断当前是否有字幕需要被保存下来
if end_time < start_time:
......@@ -374,24 +374,18 @@ def process_video(video_path: str, begin: float, end: float, book_path: str, she
mainWindow.projectContext.last_time = cur_time
subTitle, conf = detect_subtitle(frame)
print(">>>>>>>>>>>>111111111")
if subTitle is not None:
print(">>>>>>>>>>>>111111111 2222222")
subTitle = normalize(subTitle)
if len(subTitle) == 0:
print(">>>>>>>>>>>>111111111 3333333")
subTitle = None
print(">>>>>>>>>>>>222222222")
# 第一次找到字幕
if lastSubTitle is None and subTitle is not None:
start_time = cur_time
print(">>>>>>>>>>>>333333333")
# 字幕消失
elif lastSubTitle is not None and subTitle is None:
print(">>>>>>>>>>>>4444444444")
end_time = cur_time
res.append([start_time, end_time, lastSubTitle])
if (len(res) == 1 and res[-1][0] - last_time >= 1) or (len(res) > 1 and res[-1][0] - res[-2][1]) >= 1:
......@@ -399,16 +393,15 @@ def process_video(video_path: str, begin: float, end: float, book_path: str, she
recommend_lens = int((res[-1][0] - last_time) * normal_speed) if len(res) == 1 else int(
(res[-1][0] - res[-2][1]) * normal_speed)
# write_to_sheet(book_path, sheet_name, ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
# add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '%d' % recommend_lens])
print(start_time, end_time, lastSubTitle)
# write_to_sheet(book_path, sheet_name, [round(start_time, 2), round(end_time, 2), lastSubTitle, ''])
add_to_list(mainWindow, "字幕", [round(start_time, 3), round(end_time, 3), lastSubTitle, ''])
elif lastSubTitle is not None and subTitle is not None:
print(">>>>>>>>>>>>5555555555")
# 两句话连在一起,但是两句话不一样
if string_similar(lastSubTitle, subTitle) < 0.7:
print(">>>>>>>>>>>66666666666")
if string_similar(lastSubTitle, subTitle) < 0.6:
end_time = cur_time
res.append([start_time, end_time, lastSubTitle])
if (len(res) == 1 and res[-1][0] - last_time >= 1) or (len(res) > 1 and res[-1][0] - res[-2][1]) >= 1:
......@@ -416,13 +409,13 @@ def process_video(video_path: str, begin: float, end: float, book_path: str, she
recommend_lens = int((res[-1][0] - last_time) * normal_speed) if len(res) == 1 else int(
(res[-1][0] - res[-2][1]) * normal_speed)
# write_to_sheet(book_path, sheet_name, ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
# add_to_list(mainWindow, "旁白", ['', '', '', '插入旁白,推荐字数为%d' % recommend_lens])
add_to_list(mainWindow, "旁白", ['', '', '', '%d' % recommend_lens])
print(start_time, end_time, lastSubTitle)
# write_to_sheet(book_path, sheet_name, [round(start_time, 2), round(end_time, 2), lastSubTitle, ''])
add_to_list(mainWindow, "字幕", [round(start_time, 3), round(end_time, 3), lastSubTitle, ''])
start_time = end_time
else:
print(">>>>>>>>>>>>777777777")
lastSubTitle = subTitle if conf > lastConf else lastSubTitle
continue
# 当前字幕与上一段字幕不一样
......@@ -430,27 +423,66 @@ def process_video(video_path: str, begin: float, end: float, book_path: str, she
lastConf = conf
def add_to_list(mainWindow: MainWindow, element_type: str, li: list):
st_time_sec, ed_time_sec, subtitle, suggest = li
st_time_sec, ed_time_sec = str(st_time_sec), str(ed_time_sec)
# 默认使用配置文件中的语速
speed = mainWindow.projectContext.speaker_speed
aside_head_time = float(reverse_time_to_seconds(mainWindow.aside_head_time)) if mainWindow.aside_head_time != None else float(0)
st_time_sec, ed_time_sec, subtitle, suggest = li
print(">>>>>>>>start time:")
print(aside_head_time)
print(st_time_sec)
if (st_time_sec != None and st_time_sec != "" and aside_head_time > float(st_time_sec)):
print(">>>>>>need del")
print(st_time_sec)
if not mainWindow.add_head_aside:
new_element = Element('0.00', "", "", "0/100", "",speed)
mainWindow.projectContext.aside_list.append(new_element)
mainWindow.projectContext.all_elements.append(mainWindow.projectContext.aside_list[-1])
mainWindow.last_aside_index = len(mainWindow.projectContext.all_elements) - 1
mainWindow.add_head_aside = True
return
st_time_sec, ed_time_sec = str(st_time_sec), str(ed_time_sec)
aside = ""
i = len(mainWindow.projectContext.all_elements)
if element_type == "字幕":
mainWindow.projectContext.subtitle_list.append(Element(st_time_sec, ed_time_sec, subtitle, suggest, aside,speed))
new_element = Element(st_time_sec, ed_time_sec, subtitle, suggest, aside,speed)
new_element.print_self()
if mainWindow.last_aside_index != None and mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec == "" and new_element.ed_time_sec != "":
mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec = new_element.st_time_sec
if float(mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec) - float(mainWindow.projectContext.all_elements[mainWindow.last_aside_index].st_time_sec) < 2:
# print(">>>>>>>>>>>remove short aside")
mainWindow.projectContext.aside_list.remove(mainWindow.projectContext.all_elements[mainWindow.last_aside_index])
mainWindow.projectContext.all_elements.remove(mainWindow.projectContext.all_elements[mainWindow.last_aside_index])
mainWindow.last_aside_index = None
mainWindow.projectContext.subtitle_list.append(new_element)
mainWindow.projectContext.all_elements.append(mainWindow.projectContext.subtitle_list[-1])
else:
if i == 0:
st_time_sec = "0.01"
else:
if mainWindow.projectContext.all_elements[i - 1].ed_time_sec == "":
return
st_time_sec = "%.2f" % (float(mainWindow.projectContext.all_elements[i - 1].ed_time_sec) + 0.01)
# 因为暂时没有用到ed_time_sec,所以直接赋值空吧
ed_time_sec = ""
mainWindow.projectContext.aside_list.append(Element(st_time_sec, ed_time_sec, subtitle, suggest, aside,speed))
new_element = Element(st_time_sec, ed_time_sec, subtitle, suggest, aside,speed)
new_element.print_self()
if mainWindow.last_aside_index != None and mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec == "" and new_element.ed_time_sec != "":
mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec = new_element.st_time_sec
if float(mainWindow.projectContext.all_elements[mainWindow.last_aside_index].ed_time_sec) - float(mainWindow.projectContext.all_elements[mainWindow.last_aside_index].st_time_sec) < 2:
# print(">>>>>>>>>>>remove short aside")
mainWindow.projectContext.aside_list.remove(mainWindow.projectContext.all_elements[mainWindow.last_aside_index])
mainWindow.projectContext.all_elements.remove(mainWindow.projectContext.all_elements[mainWindow.last_aside_index])
mainWindow.last_aside_index = None
new_element.suggest = "0/" + new_element.suggest
if (st_time_sec != None and st_time_sec != "" and aside_head_time > float(st_time_sec)):
return
mainWindow.projectContext.aside_list.append(new_element)
mainWindow.projectContext.all_elements.append(mainWindow.projectContext.aside_list[-1])
mainWindow.last_aside_index = len(mainWindow.projectContext.all_elements) - 1
def detect_with_ocr(video_path: str, book_path: str, start_time: float, end_time: float, state=None, mainWindow: MainWindow=None):
......
{
"user_name":"盲文出版社",
"dd_url_prefix":"https://oapi.dingtalk.com/robot/send?access_token=a7e6b223bc0a6e4b5e3f64b1570d0c884db0d833592f5e84b020c2896130d659",
"secret":"SEC252452789bc17cfb1e6c973f837426fa0f9fd50c8793239c070e9d3c021d8109"
}
\ No newline at end of file
......@@ -9,35 +9,44 @@ import base64
import hashlib
import urllib.parse
user_name = "盲文出版社"
dd_url_prefix = "https://oapi.dingtalk.com/robot/send?access_token=a7e6b223bc0a6e4b5e3f64b1570d0c884db0d833592f5e84b020c2896130d659"
# dd_url_prefix = "https://oapi.dingtalk.com/robot/send?access_token=12a5e64b24e7345fed2415c5c2f9101180763e327b21727cd35fdaa3fb274e74"
secret = 'SEC252452789bc17cfb1e6c973f837426fa0f9fd50c8793239c070e9d3c021d8109'
# secret = "SECb5d68b27bd2e4694667d36c0f91336f3641b3287b945906a83997353f961d415"
with open("./ding_notify.conf", "r", encoding="utf-8") as f:
json_obj = json.load(f)
# user_name = "盲文出版社"
# dd_url_prefix = "https://oapi.dingtalk.com/robot/send?access_token=a7e6b223bc0a6e4b5e3f64b1570d0c884db0d833592f5e84b020c2896130d659"
# # dd_url_prefix = "https://oapi.dingtalk.com/robot/send?access_token=12a5e64b24e7345fed2415c5c2f9101180763e327b21727cd35fdaa3fb274e74"
# secret = 'SEC252452789bc17cfb1e6c973f837426fa0f9fd50c8793239c070e9d3c021d8109'
# # secret = "SECb5d68b27bd2e4694667d36c0f91336f3641b3287b945906a83997353f961d415"
user_name = json_obj["user_name"]
dd_url_prefix = json_obj["dd_url_prefix"]
secret = json_obj["secret"]
def notify(err):
timestamp = str(round(time.time() * 1000))
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
dd_url = dd_url_prefix + "&timestamp=" + timestamp + "&sign=" + sign
h = {"Content-Type": "application/json"}
d = {
"msgtype": "markdown",
"markdown": {
"title": "msg",
"text": "| 用户名称:%s \n" % (user_name) +
"\n" +
"| 异常时间:%s \n" % (time.strftime('%Y:%m:%d %H:%M:%S', time.localtime(int(time.time())))) +
"\n" +
"| 异常信息:%s \n" % (err)
try:
timestamp = str(round(time.time() * 1000))
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)
dd_url = dd_url_prefix + "&timestamp=" + timestamp + "&sign=" + sign
h = {"Content-Type": "application/json"}
d = {
"msgtype": "markdown",
"markdown": {
"title": "msg",
"text": "| 用户名称:%s \n" % (user_name) +
"\n" +
"| 异常时间:%s \n" % (time.strftime('%Y:%m:%d %H:%M:%S', time.localtime(int(time.time())))) +
"\n" +
"| 异常信息:%s \n" % (err)
}
}
}
r = requests.post(dd_url, json.dumps(d), headers=h)
print(r.status_code)
print(r.text)
\ No newline at end of file
r = requests.post(dd_url, json.dumps(d), headers=h)
print(r.status_code)
print(r.text)
except Exception as e:
print("ding notify err")
print(e)
\ No newline at end of file
......@@ -4,6 +4,8 @@ import openpyxl
from management import Element
from utils import reverse_time_to_seconds, get_seconds
def read_xls(file_path):
print("read_xls")
elements = []
......@@ -26,20 +28,20 @@ def read_xls(file_path):
cell_value = str(cell_value) if cell_value != None else ""
# print(cell_value)
if col_index == 0:
start_time = cell_value if cell_value != None else ""
start_time = get_seconds(cell_value) if cell_value != None else ""
if col_index == 1:
end_time = get_seconds(cell_value) if cell_value != None else ""
if col_index == 2:
end_time = cell_value if cell_value != None else ""
if col_index == 4:
subtitle = cell_value if cell_value != None else ""
if col_index == 5:
if col_index == 3:
if cell_value == None or cell_value == "":
break
suggest = cell_value if cell_value != None else ""
if col_index == 6:
if col_index == 4:
if cell_value == None or cell_value == "":
break
aside = cell_value if cell_value != None else ""
if col_index == 7:
if col_index == 5:
speed = cell_value if cell_value != None else ""
col_index = col_index + 1
if suggest != "" and aside != "":
......@@ -71,33 +73,39 @@ def read_xlsx(file_path):
cell_value = str(cell_value) if cell_value != None else ""
# print(cell_value)
if col_index == 0:
start_time = cell_value if cell_value != None else ""
start_time = get_seconds(cell_value) if cell_value != None else ""
if col_index == 1:
end_time = get_seconds(cell_value) if cell_value != None else ""
if col_index == 2:
end_time = cell_value if cell_value != None else ""
if col_index == 4:
subtitle = cell_value if cell_value != None else ""
if col_index == 5:
if col_index == 3:
if cell_value == None or cell_value == "":
break
suggest = cell_value if cell_value != None else ""
if col_index == 6:
if col_index == 4:
if cell_value == None or cell_value == "":
break
aside = cell_value if cell_value != None else ""
if col_index == 7:
if col_index == 5:
speed = cell_value if cell_value != None else ""
col_index = col_index + 1
if suggest != "" and aside != "":
if suggest != None and suggest != "" and aside != None and aside != "":
new_element = Element(start_time, end_time, subtitle, suggest, aside, speed)
# new_element.print_self()
new_element.print_self()
elements.append(new_element)
checkLength(elements)
print("element size:")
print(len(elements))
return elements
def checkLength(elements):
for element in elements:
if int("".join(filter(str.isdigit, element.suggest))) < len(element.aside):
# if int("".join(filter(str.isdigit, element.suggest))) < len(element.aside):
# raise Exception("旁白字数没有按照推荐要求")
if int(element.suggest.split("/")[1]) < len(element.aside):
raise Exception("旁白字数没有按照推荐要求")
else:
element.suggest = str(len(element.aside)) + "/" + element.suggest.split("/")[1]
# elements = read_xlsx("C:/Users/AIA/Desktop/1/121/1.xlsx")
# print(len(elements))
......
import subprocess
import os
import subprocess
import math
import time
import shutil
def calculate_audio_volume(file_path):
# 使用FFmpeg获取音频分贝值
command = [
'res/ffmpeg-4.3.1/bin/ffmpeg', '-i', file_path,
'-af', 'volumedetect', '-f', 'null', '-'
]
print(command)
result = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
output = result.stderr
# 从输出中解析分贝值
for line in output.split('\n'):
if 'mean_volume' in line:
print(line)
a = float(line.split(':')[1].strip().split("d")[0].strip())
print(a)
# mean_volume = float((line.split(':')[1].strip()).split(" ")[0])
return a
return None
# def adjust_audio_volume(input_file, output_file, multiplier):
# # 使用FFmpeg将音频音量设置为给定倍数
# command = [
# 'ffmpeg', '-i', input_file,
# '-af', f'volume={multiplier}*', output_file
# ]
# subprocess.run(command)
def adjust_audio_volume(input_file, volume_adjustment):
temp_path = "./temp.wav"
command = [
"res/ffmpeg-4.3.1/bin/ffmpeg",
"-i", input_file,
"-af", f"volume={volume_adjustment}",
"-y", # 覆盖输出文件,加上此选项
temp_path # 输出文件与输入文件相同
]
subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
os.remove(input_file)
# os.rename(temp_path, input_file)
shutil.move(temp_path, input_file)
def cg_wav(first_file_path, second_file_path, rate):
try:
print(first_file_path, second_file_path, str(rate))
# 计算第一个文件的音量
first_file_volume = calculate_audio_volume(first_file_path)
if first_file_volume is not None:
# 计算第二个文件的音量并计算倍数
second_file_volume = calculate_audio_volume(second_file_path)
if second_file_volume is not None:
# volume_multiplier = 10 ** ((first_file_volume - second_file_volume) / 20) # 转换为幅度倍数
# # 调整第二个文件的音量
# adjusted_output_file = 'path/to/output/adjusted_file.wav'
# 计算第二个文件应改为自身的大小的倍数
volume_difference_db = first_file_volume - second_file_volume
volume_difference_linear = 10 ** (volume_difference_db / 20) # 转换为线性倍数
adjusted_multiplier = volume_difference_linear * rate
adjust_audio_volume(second_file_path, adjusted_multiplier)
else:
print("无法计算第二个文件的音量")
else:
print("无法计算第一个文件的音量")
except Exception as e:
print("cg_wav err")
print(e)
# cg_wav("C:/Users/Administrator/Desktop/无障碍电影/fuiii0000/output/0.01.wav","C:/Users/Administrator/Desktop/无障碍电影/fuiii0000\output\0.01.wav",0.26)
# calculate_audio_volume("./0.01.wav")
# adjust_audio_volume("./0.01.wav",1.335)
# calculate_audio_volume("./0.01.wav")
# def test(projectContext):
# from split_wav import extract_audio
# video_path = projectContext.video_path
# output_dir = os.path.join(projectContext.project_base_dir, "output")
# extract_audio(video_path, output_dir, 0, -1)
# self.projectContext.video_path
# output_dir = os.path.join(self.projectContext.project_base_dir, "output")
# files = os.listdir(output_dir):
# for i, f in enumerate(files):
# fname = '.'.join(f.split('.')[:-1])
# try:
# st_time = float(fname)
# cur_audio, _ = soundfile.read(os.path.join(output_dir, f))
# # print(len(cur_audio))
# st_index = int(st_time * freq)
# audio_len = len(cur_audio)
# blank_audio[st_index: st_index + audio_len] = cur_audio
# origin_wav[st_index: st_index + audio_len] *= origin_audio_rate
# state[0] = float((i + 1) / len(files)) * 0.6 + 0.2
# except:
# continue
\ No newline at end of file
......@@ -40,14 +40,62 @@ import re
from ding_utils import notify
from excel_utils import read_xls,read_xlsx
from ffmpeg_util import adjust_audio_volume
from PyQt5.QtCore import QThread;
# from emit_import_event import emit_import_event
class WorkerThread(QThread):
def __init__(self, main_window,elements):
super().__init__()
self.main_window = main_window
self.elements = elements
def run(self):
# 在后台执行耗时操作
state = [None]
self.main_window.state = state
self.main_window.threads = []
t = RunThread(funcName=self.main_window.batch_add_line_operation_slot,
args=(self.elements, state, self),
name="batch_add_line_operation_slot")
t.setDaemon(True)
self.main_window.threads.append(t)
self.main_window.all_threads.append(t)
for t in self.main_window.threads:
t.start()
def refresh(self):
self.main_window.import_process_sign.emit(self.elements)
class CustomDelegate(QtWidgets.QStyledItemDelegate):
def paint(self, painter, option, index):
# Customize the painting behavior for the specific column
if index.column() == 0: # Replace with the desired column index
option.state |= QtWidgets.QStyle.State_Selected
# option.state |= QtWidgets.QStyle.State_HasFocus
super().paint(painter, option, index)
class MainWindow(QMainWindow, Ui_MainWindow):
EXIT_CODE_REBOOT = -12345678
renew_signal = pyqtSignal(str)
import_process_sign = pyqtSignal(list)
refresh_sign = pyqtSignal()
def __init__(self, project_path):
super(MainWindow, self).__init__()
self.last_aside_index = None
self.setupUi(self)
self.statusbar.showMessage("hello", 5000)
self.projectContext = ProjectContext()
......@@ -68,7 +116,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.assemble_dialog.start_assemble_signal.connect(
self.synthesis.synthesis_slot)
self.create_dialog = Create_Dialog()
self.create_dialog = Create_Dialog(self)
self.create_dialog.init_project_signal.connect(self.init_project)
# 工程导出相关组件
......@@ -86,6 +134,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.continue_detect_prompt_dialog = Prompt_Dialog(
self.continue_detect)
# 导入旁白提示框
self.import_excel_dialog = Prompt_Dialog()
# 操作框
self.operation_dialog = Operation_Dialog(self)
self.operation_dialog.start_add_signal.connect(
......@@ -97,6 +148,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.del_line_operation_slot)
# 所有QTimer集中管理
self.import_excel_timer = QTimer()
self.import_excel_timer.timeout.connect(self.check_if_import_excel_over)
self.detect_timer = QTimer()
self.detect_timer.timeout.connect(self.check_if_detect_over_slot)
self.synthesis_timer = QTimer()
......@@ -166,6 +219,19 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.insert_aside_from_now_btn.clicked.connect(
self.insert_aside_from_now_slot)
self.insert_aside_from_now_btn.setEnabled(False)
self.up_ocr_btn.clicked.connect(
self.up_ocr)
self.down_ocr_btn.clicked.connect(
self.down_ocr)
self.up_ocr_bottom_btn.clicked.connect(
self.up_ocr_bottom)
self.down_ocr_bottom_btn.clicked.connect(
self.down_ocr_bottom)
self.confirm_head_aside_btn.clicked.connect(
self.confirm_head_aside)
self.detect_btn.clicked.connect(
self.show_detect_dialog)
"""视频预览相关信息
......@@ -190,6 +256,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.sld_video.sliderMoved.connect(self.moveSlider) # 进度条拖拽跳转
self.sld_video.ClickedValue.connect(self.clickedSlider) # 进度条点击跳转
self.sld_audio.valueChanged.connect(self.volumeChange) # 控制声音播放
self.pb_sld_audio.valueChanged.connect(self.volumeChangePb) # 控制声音播放
self.kd_slider.valueChanged.connect(self.scale_change_slot)
"""旁白音频预览
......@@ -223,13 +290,33 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.generateMenu)
all_tableHead = self.all_tableWidget.horizontalHeader()
all_tableHead.setSectionResizeMode(QtWidgets.QHeaderView.Fixed)
# all_tableHead.setStyleSheet("QHeaderView::section { padding: 1px;endent: 1px; margin: 1px}")
# all_tableHead.setSectionResizeMode(
# 0, QtWidgets.QHeaderView.Fixed)
# all_tableHead.resizeSection(0,100)
# all_tableHead.setSectionResizeMode(
# 1, QtWidgets.QHeaderView.Fixed)
# all_tableHead.resizeSection(1,100)
all_tableHead.setSectionResizeMode(
0, QtWidgets.QHeaderView.ResizeToContents)
all_tableHead.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
all_tableHead.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
2, QtWidgets.QHeaderView.Fixed)
all_tableHead.resizeSection(2,175)
# all_tableHead.setSectionResizeMode(
# 3, QtWidgets.QHeaderView.Fixed)
# all_tableHead.resizeSection(3,100)
all_tableHead.setSectionResizeMode(
3, QtWidgets.QHeaderView.ResizeToContents)
4, QtWidgets.QHeaderView.Fixed)
all_tableHead.resizeSection(4,390)
# all_tableHead.setSectionResizeMode(
# 6, QtWidgets.QHeaderView.Fixed)
# all_tableHead.resizeSection(6,50)
# all_tableHead.setSectionResizeMode(
# 0, QtWidgets.QHeaderView.ResizeToContents)
all_tableHead.setSectionResizeMode(0, QtWidgets.QHeaderView.Stretch)
all_tableHead.setSectionResizeMode(1, QtWidgets.QHeaderView.Stretch)
# all_tableHead.setSectionResizeMode(
# 3, QtWidgets.QHeaderView.ResizeToContents)
# all_tableHead.setSectionResizeMode(4, QtWidgets.QHeaderView.Stretch)
aside_header = self.projectContext.aside_header
self.pb_tableWidget.setColumnCount(len(aside_header))
self.pb_tableWidget.setHorizontalHeaderLabels(aside_header)
......@@ -256,6 +343,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.zm_tableWidget.itemDoubleClicked.connect(self.change_video_time)
# self.all_tableWidget.itemDoubleClicked.connect(self.change_video_time)
# self.all_tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
# self.all_tableWidget.setItemDelegateForColumn(0, CustomDelegate())
# self.all_tableWidget.setItemDelegate(CustomDelegate())
self.all_tableWidget.itemDoubleClicked.connect(self.writeHistory)
self.all_tableWidget.itemChanged.connect(self.rewriteHistory)
self.all_tableWidget.itemChanged.connect(self.write2ProjectFromContent)
......@@ -299,13 +390,41 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.projectContext.Init(project_path)
self.update_ui()
self.rate = 0
self.rate = None
self.rate_bottom = None
self.origin_rate = 100.00
self.pb_rate = 100.00
self.pb_cg_rate = 1.00
self.sld_video.setFocus()
self.aside_head_time = None
self.add_head_aside = False
# 打印到log文件中
t = RunThread(funcName=make_print_to_file, args=os.path.join(os.getcwd(), 'log'), name="logging")
print(t)
make_print_to_file(os.path.join(os.getcwd(), 'log'))
get_focus_thread = RunThread(funcName=self.getFocus, name="get_focus_thread")
get_focus_thread.setDaemon(True)
get_focus_thread.start()
def getFocus(self):
while(True):
if(not self.is_user_editing()):
self.setFocus()
time.sleep(1)
def keyPressEvent(self, event):
if event.key()==Qt.Key_Left:
self.sld_video.setValue(self.sld_video.value() - 5 if self.sld_video.value() >=5 else 0)
self.clickedSlider(self.sld_video.value())
# print(">>>>>>press Left")
if event.key()==Qt.Key_Right:
print(self.sld_video.maximum())
self.sld_video.setValue(self.sld_video.value() + 5 if self.sld_video.value() < self.sld_video.maximum() - 5 else self.sld_video.maximum() -1)
self.clickedSlider(self.sld_video.value())
# print(">>>>>>press Right")
def generateMenu(self, pos):
"""当用户右击字幕旁白表格时,弹出菜单项
......@@ -376,8 +495,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""弹出旁白区间检测相关信息填写窗口
"""
if self.rate == None:
self.prompt_dialog.show_with_msg("请选择字幕上边界范围")
return
if self.rate_bottom == None:
self.prompt_dialog.show_with_msg("请选择字幕下边界范围")
return
self.detect_dialog.init_self()
self.detect_dialog.show()
def start_detect_direct(self):
self.detect_dialog.init_self()
self.detect_dialog.start_detect()
def show_assemble_dialog(self):
"""弹出旁白音频合成相关信息填写窗口
......@@ -457,17 +586,35 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.action_operate.setEnabled(True)
self.action_insert_aside_from_now.setEnabled(True)
self.insert_aside_from_now_btn.setEnabled(True)
# print(">>>>>>>>>>>>>>>start detect")
# self.start_detect_direct()
def play_video(self,path):
self.player.setMedia(QMediaContent(path)) # 选取视频文件
self.playVideo()
video_path = path.path()
self.projectContext.video_path = video_path[1:]
excel_name = os.path.splitext(os.path.basename(video_path))[0]
self.projectContext.excel_path = os.path.join(
self.projectContext.project_base_dir, excel_name + ".xlsx")
self.action_export.setEnabled(True)
self.action_operate.setEnabled(True)
self.action_insert_aside_from_now.setEnabled(True)
self.insert_aside_from_now_btn.setEnabled(True)
def up_ocr(self):
self.widget.change_painter_flag(True)
h = self.widget.up(3)
video_h = self.wgt_video.height()
self.rate = float(h-10)/float(video_h)
print(">>>>>video_h: "+str(video_h))
print(">>>>>up h:" + str(h))
print(self.wgt_video.height())
print(">>>>>>>>>rate" + str(self.rate))
def down_ocr(self):
self.widget.change_painter_flag(True)
h = self.widget.down(3)
video_h = self.wgt_video.height()
self.rate = float(h-10)/float(video_h)
......@@ -476,44 +623,62 @@ class MainWindow(QMainWindow, Ui_MainWindow):
print(">>>>>>>>>rate" + str(self.rate))
def up_ocr_bottom(self):
self.widget_bottom.change_painter_flag(True)
h = self.widget_bottom.up(3)
video_h = self.wgt_video.height()
self.rate_bottom = float(h-6)/float(video_h)
def down_ocr_bottom(self):
self.widget_bottom.change_painter_flag(True)
h = self.widget_bottom.down(3)
video_h = self.wgt_video.height()
self.rate_bottom = float(h-6)/float(video_h)
def refresh_on_import(self):
print(">>>>>>>refresh in")
self.refresh_tab_slot()
#导入旁白excel
def import_excel(self):
# excel_path = self.openExcelFile()
# print(excel_path)
# elements = None
# if excel_path.endswith("xls"):
# elements = read_xls(excel_path)
# else:
# elements = read_xlsx(excel_path)
# if elements != None and len(elements) > 0:
# self.batch_add_line_operation_slot(elements)
try:
excel_path = self.openExcelFile()
print(excel_path)
elements = None
if excel_path.endswith("xls"):
elements = read_xls(excel_path)
else:
elif excel_path.endswith("xlsx"):
elements = read_xlsx(excel_path)
else:
self.import_excel_dialog.show_with_msg("请选择正确的excel文件")
return
if elements != None and len(elements) > 0:
self.batch_add_line_operation_slot(elements)
# self.widget.change_painter_flag(False)
# self.widget_bottom.change_painter_flag(False)
self.statusbarLabel.setText("准备导入:")
self.progressBar.setValue(0)
self.worker_thread = WorkerThread(self, elements)
self.import_excel_timer.start(5000)
self.import_process_sign.connect(self.import_process)
self.refresh_sign.connect(self.refresh_on_import)
self.worker_thread.start()
# self.import_excel_dialog.show_with_msg("请等待导入进度完成")
else:
self.import_excel_dialog.show_with_msg("没有要更新的旁白内容")
except Exception as e:
print("import excel err")
print(e)
notify(e)
self.prompt_dialog.show_with_msg("导入旁白失败,请检查模板及内容: " + e.args[0])
self.import_excel_dialog.show_with_msg("导入旁白失败,请检查模板及内容: " + e.args[0])
def import_process(self,elements):
print(">>>>>>>>>>>into import process")
print(len(elements))
self.refresh_all_tab_slot()
# self.widget.change_painter_flag(True)
# self.widget_bottom.change_painter_flag(True)
"""导入视频,并对主界面中的相关控件进行对应更新
"""
......@@ -619,6 +784,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.show_warning_msg_box("请输入视频文件路径")
return
elif not os.path.exists(video_path):
print(">>>>>>>>>>>video path:" + video_path)
self.show_warning_msg_box("请确认视频文件是否存在")
return
if len(book_path) == 0:
......@@ -677,7 +843,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.all_threads.append(t)
for t in self.threads:
t.start()
try:
t.start()
except Exception as e:
print(e)
print("===子线程已经开启 in detect ===")
self.statusbarLabel.setText(" 准备检测:")
......@@ -702,6 +871,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""
self.check_if_over("导出")
def check_if_import_excel_over(self):
"""确认自动渲染导出任务是否完成
"""
self.check_if_over("旁白导入")
# type = 检测 或 合成 或 导出
def check_if_over(self, type: str):
"""确认传入的待检测任务是否完成
......@@ -729,6 +904,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
elif type == "检测":
self.detect_timer.stop()
self.refresh_tab_timer.stop()
elif type == "旁白导入":
self.import_excel_timer.stop()
# self.refresh_tab_timer.stop()
else:
self.export_timer.stop()
......@@ -827,8 +1005,27 @@ class MainWindow(QMainWindow, Ui_MainWindow):
volume = round(position/self.sld_audio.maximum()*100)
print("vlume %f" % volume)
self.player.setVolume(volume)
self.origin_rate = volume if volume >0 else 1
self.pb_cg_rate = self.pb_rate / self.origin_rate
print(">>>>>>>>>>cg rate :" + str(self.pb_cg_rate))
self.lab_audio.setText("音量:" + str(volume) + "%")
def volumeChangePb(self, position: int):
"""根据当前音量条调整音量
Args:
position (int): 当前音量条的选值
"""
volume = round(position/self.pb_sld_audio.maximum()*100)
print("vlume %f" % volume)
# self.player.setVolume(volume)
self.pb_audio.setText("旁白音量:" + str(volume) + "%")
self.pb_rate = volume if volume >0 else 1
self.pb_cg_rate = self.pb_rate / self.origin_rate
print(">>>>>>>>>>cg rate :" + str(self.pb_cg_rate))
print("vlume %f" % self.pb_rate)
# postion 取值[0,self.sld_video.maximum()]
def clickedSlider(self, position: int):
"""点击时间轴时,对应切换视频播放进度
......@@ -838,6 +1035,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
根据当前浮标在时间轴上的位置对应切换视频的播放进度,并更新视频播放进度标签
"""
print(">>>>>>>>>>click slider:" + str(position))
if self.player.duration() > 0: # 开始播放后才允许进行跳转
video_position = int(
(position / self.sld_video.maximum()) * self.player.duration())
......@@ -922,12 +1120,26 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return path
def openExcelFile(self):
path = QFileDialog.getOpenFileUrl(self, "选择待导入Excel", QUrl(
os.getcwd()), "Excel Files(*.xls *xlsx *.);; 所有文件(*.*)")[0]
# path = QFileDialog.getOpenFileUrl(self, "选择待导入Excel", QUrl(
# os.getcwd()), "Excel Files(*.xls *xlsx *.);; 所有文件(*.*)")[0]
# # print(path.url()[8:])
# print(path)
# print(path.url()[8:])
print(path)
print(path.url()[8:])
return path.url()[8:]
# return path.url()[8:]
options = QFileDialog.Options()
options |= QFileDialog.ReadOnly
options |= QFileDialog.DontUseNativeDialog
file_dialog = QFileDialog()
file_dialog.setOptions(options)
file_dialog.setFileMode(QFileDialog.ExistingFile)
file_dialog.setNameFilter("Excel Files (*.xls *.xlsx)")
if file_dialog.exec_() == QFileDialog.Accepted:
selected_files = file_dialog.selectedFiles()
if selected_files:
return selected_files[0]
return ""
# 在初始化工程时
def init_ProjectContext_VideoPath(self, path: str):
......@@ -1008,11 +1220,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# self.all_tableWidget.clear()
self.all_tableWidget.setRowCount(len(all_elements))
if need_refresh_all:
self.all_tableWidget.clearContents()
st_idx = 0 if need_refresh_all else self.all_tableWidget_idx
for i in range(st_idx, len(all_elements)):
# suggest = all_elements[i].suggest
# if suggest != None and suggest != "":
# arrays = suggest.split("/")
# if len(arrays) == 2:
# all_elements[i].suggest = (str(len(all_elements[i].aside)) if all_elements[i].aside != None and all_elements[i].aside != "" else "0") + "/" + arrays[1]
# else:
# all_elements[i].suggest = (str(len(all_elements[i].aside)) if all_elements[i].aside != None and all_elements[i].aside != "" else "0") + "/" + arrays[0]
self.setElememtToTable(self.all_tableWidget, all_elements[i], i)
self.all_tableWidget_idx = self.all_tableWidget_idx + 1
self.all_tableWidget_idx = len(all_elements)
# self.all_tableWidget_idx = len(all_elements)
self.pb_tableWidget_idx = len(aside_list)
self.zm_tableWidget_idx = len(subtitle_list)
# self.all_tableWidget.resizeRowsToContents()
......@@ -1037,7 +1259,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
elem_list = elem.to_short_list()
time_format_col_list = constant.Content.TimeFormatColumns
btn = QPushButton()
btn.setText(f"预览{idx}")
# btn.setText(f"预览{idx}")
btn.setText(f"预览")
col = len(elem_list)
btn.clicked.connect(self.audio_preview_slot_all)
table.setCellWidget(idx, col, btn)
......@@ -1048,7 +1271,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
elem_list = elem.to_aside_list()
time_format_col_list = constant.Aside.TimeFormatColumns
btn = QPushButton()
btn.setText(f"预览{idx}")
# btn.setText(f"预览{idx}")
btn.setText(f"预览")
col = len(elem_list)
btn.clicked.connect(self.audio_preview_slot)
table.setCellWidget(idx, col, btn)
......@@ -1079,9 +1303,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
table.setCellWidget(idx, j, qcombo)
else:
item = QTableWidgetItem(text)
item.setTextAlignment(Qt.AlignCenter)
# 设置为不可编辑
if self.checkIfTableItemCanChange(table, idx, j) == False:
item.setFlags(Qt.ItemIsEnabled)
# item.setFlags(Qt.ItemIsEnabled)
print(1)
table.setItem(idx, j, item)
# 只有Content页的字幕列和 Aside页的字幕列 可编辑
......@@ -1134,7 +1360,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# 获取时间
item = self.all_tableWidget.item(idx.row(), 0)
audio_path = None
pos_sec = utils.trans_to_seconds(item.text())
pos_sec = float(utils.get_seconds(self.projectContext.all_elements[int(idx.row())].st_time_sec))
# pos_sec = utils.trans_to_seconds(item.text())
audio_path = os.path.dirname(self.projectContext.excel_path) + (
"/tmp/%.3f.wav" % pos_sec)
print("待播放的音频文件为", audio_path)
......@@ -1202,16 +1429,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
row = item.row() # 获取行数
col = item.column() # 获取列数
print("row, col = %s, %s" % (row, col))
text = item.text() # 获取内容
# text = item.text() # 获取内容
pre_item = self.all_tableWidget.item(row, 0)
text = pre_item.text() # 获取内容
# 停下旁白预览
self.audio_player.setMedia(QMediaContent())
if self.checkIfVideoTimeCanChange(col):
self.video_timer.stop()
# 双击的时候,就重启计时器,避免他跳转回video.position的地方去。
self.video_timer.start(1000)
sec_float = utils.trans_to_seconds(text)
self.player.setPosition(int(float(sec_float)*1000))
# if self.checkIfVideoTimeCanChange(col):
self.video_timer.stop()
# 双击的时候,就重启计时器,避免他跳转回video.position的地方去。
self.video_timer.start(1000)
sec_float = utils.trans_to_seconds(text)
self.player.setPosition(int(float(sec_float)*1000))
def checkIfVideoTimeCanChange(self, col: int) -> bool:
"""检查双击的单元格是否为起始时间列中的单元格
......@@ -1291,6 +1520,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
在set表格的时候(初始化),不会触发。只有双击修改或切换语速时才会触发
"""
try:
# 不需要set为False
row = item.row() # 获取行数
col = item.column() # 获取列数 注意是column而不是col
# 只有更新语速或者更新旁白,才需要重新生成音频
if col not in constant.Content.ActivateColumns:
return
if self.projectContext.initial_ing == True:
return
if item is None:
......@@ -1301,12 +1536,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
return
self.set_user_edit(False)
# 不需要set为False
row = item.row() # 获取行数
col = item.column() # 获取列数 注意是column而不是col
# 只有更新语速或者更新旁白,才需要重新生成音频
if col not in constant.Content.ActivateColumns:
return
# 停止预览,释放当前占用的音频文件
self.audio_player.setMedia(QMediaContent())
......@@ -1327,8 +1557,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
from speech_synthesis import speech_synthesis, Speaker, choose_speaker
audio_dir = os.path.dirname(self.projectContext.excel_path)
wav_path = audio_dir + \
'/tmp/%.3f.wav' % float(
self.projectContext.all_elements[int(row)].st_time_sec)
'/tmp/%.3f.wav' % float(utils.reverse_time_to_seconds(self.projectContext.all_elements[int(row)].st_time_sec))
print("wav_path:", wav_path)
try:
# speed_info = self.projectContext.speaker_speed
......@@ -1545,6 +1774,22 @@ class MainWindow(QMainWindow, Ui_MainWindow):
col = item.column() # 获取列数 注意是column而不是col哦
text = item.text() # 获取内容
pre_item = self.all_tableWidget.item(row, col - 1)
suggest = pre_item.text()
if suggest != None and suggest != "":
arrays = suggest.split("/")
if len(arrays) == 2:
suggest = str(len(text)) + "/" + arrays[1]
if len(text) > int(arrays[1]):
self.import_excel_dialog.show_with_msg("旁白字数不能超过推荐字数")
return
else:
suggest = str(len(text)) + "/" + arrays[0]
if len(text) > int(arrays[0]):
self.import_excel_dialog.show_with_msg("旁白字数不能超过推荐字数")
return
if col not in constant.Content.ActivateColumns:
return
# 更新【字幕旁白】这个tab里的字,如果是语速,那就更新语速这一列,如果是旁白,那就更新旁白这一列
......@@ -1562,6 +1807,12 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# self.all_tableWidget.setItem(
# int(idx), constant.Content.SpeedColumnNumber, QTableWidgetItem(text))
self.projectContext.refresh_speed(row, text)
# self.all_tableWidget_idx = int(row)
# self.set_table_to_window(False)
pre_item.setText(suggest)
except Exception as e:
print(e)
......@@ -1569,20 +1820,24 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""撤销之前对表格内容的修改操作
"""
self.can_write_history = False
self.user_editing_aside = True
record = self.projectContext.history_pop()
print('[undo_slot] record=%s' % (record.to_string()))
item = QTableWidgetItem(record.old_str)
row = int(record.row)
# self.projectContext.aside_list[row].aside = record.old_str
# self.pb_tableWidget.setItem(
# row, constant.Aside.AsideColumnNumber, item)
self.projectContext.all_elements[row].aside = record.old_str
self.all_tableWidget.setItem(
row, constant.Content.AsideColumnNumber, item)
self.action_redo.setEnabled(True)
try:
self.can_write_history = False
self.user_editing_aside = True
record = self.projectContext.history_pop()
print('[undo_slot] record=%s' % (record.to_string()))
item = QTableWidgetItem(record.old_str)
row = int(record.row)
# self.projectContext.aside_list[row].aside = record.old_str
# self.pb_tableWidget.setItem(
# row, constant.Aside.AsideColumnNumber, item)
self.projectContext.all_elements[row].aside = record.old_str
self.all_tableWidget.setItem(
row, constant.Content.AsideColumnNumber, item)
self.action_redo.setEnabled(True)
except Exception as e:
print("undo slot err")
print(e)
def redo_slot(self):
"""重做之前撤销的对表格内容的修改操作
......@@ -1650,8 +1905,11 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if not self.is_user_editing() and self.curTab == 0:
all_elements = self.projectContext.all_elements
for i in range(len(all_elements) - 1, -1, -1):
if utils.trans_to_seconds(all_elements[i].st_time_sec) <= cur_time:
# if utils.trans_to_seconds(all_elements[i].st_time_sec) <= cur_time:
if float(utils.get_seconds(all_elements[i].st_time_sec)) <= cur_time:
self.all_tableWidget.selectRow(i)
# self.all_tableWidget.setCurrentCell(i, 0) # 选中整行
# self.all_tableWidget.setStyleSheet("QTableView::item:selected { background-color: yellow; }") # 应用高亮样式
break
# elif self.curTab == 1:
# subtitle_list = self.projectContext.subtitle_list
......@@ -1687,6 +1945,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.set_table_to_window(need_refresh_all=False)
self.projectContext.save_project(False)
def refresh_all_tab_slot(self):
"""刷新整个表格
将表格内容更新至界面中,并保存当前工程内容
"""
self.set_table_to_window(need_refresh_all=True)
self.projectContext.save_project(False)
def export_all(self):
"""导出无障碍电影视频
......@@ -1695,7 +1962,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""
output_dir = os.path.join(self.projectContext.project_base_dir, "output")
if os.path.exists(output_dir) and len(os.listdir(output_dir)) > 0:
self.export.export_slot(self.projectContext.video_path, output_dir)
self.export.export_slot(self.projectContext.video_path, output_dir, self.pb_cg_rate)
else:
self.prompt_dialog.show_with_msg("暂时无合成音频,请至少生成一条\n 旁白音频后再尝试导出")
......@@ -1721,10 +1988,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
print("[insert_aside_from_now_slot] idx=", idx)
# 其实end_time目前是没啥用的,可以删掉了
print("cur_lens", len(self.projectContext.all_elements))
# if idx < len(self.projectContext.all_elements) - 1:
# self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx+1].st_time_sec, "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
# else:
# self.add_line_operation_slot(idx, str(cur_time), str(cur_time+1), "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
if self.projectContext.all_elements[idx - 1].ed_time_sec == None or self.projectContext.all_elements[idx - 1].ed_time_sec == "":
self.projectContext.all_elements[idx - 1].ed_time_sec = self.projectContext.all_elements[idx - 1].st_time_sec
if idx < len(self.projectContext.all_elements) - 1:
self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx+1].st_time_sec, "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
# self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx].st_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
if idx == 0:
self.add_line_operation_slot(idx, self.projectContext.all_elements[idx].st_time_sec, self.projectContext.all_elements[idx].st_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
else:
self.add_line_operation_slot(idx, self.projectContext.all_elements[idx - 1].ed_time_sec, self.projectContext.all_elements[idx].st_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
else:
self.add_line_operation_slot(idx, str(cur_time), str(cur_time+1), "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
self.add_line_operation_slot(idx, self.projectContext.all_elements[idx - 1].ed_time_sec, str(cur_time+1), "", "0/100", "", self.projectContext.speaker_speed)
def insert_aside_from_cur_time(self,cur_time:float):
"""在当前位置插入旁白
......@@ -1741,10 +2019,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
print("[insert_aside_from_now_slot] idx=", idx)
# 其实end_time目前是没啥用的,可以删掉了
print("cur_lens", len(self.projectContext.all_elements))
# if idx < len(self.projectContext.all_elements) - 1:
# self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx+1].st_time_sec, "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
# else:
# self.add_line_operation_slot(idx, str(cur_time), str(cur_time+1), "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
if self.projectContext.all_elements[idx - 1].ed_time_sec == None or self.projectContext.all_elements[idx - 1].ed_time_sec == "":
self.projectContext.all_elements[idx - 1].ed_time_sec = self.projectContext.all_elements[idx - 1].st_time_sec
if idx < len(self.projectContext.all_elements) - 1:
self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx+1].st_time_sec, "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
# self.add_line_operation_slot(idx, str(cur_time), self.projectContext.all_elements[idx].st_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
self.add_line_operation_slot(idx, self.projectContext.all_elements[idx - 1].ed_time_sec, self.projectContext.all_elements[idx].st_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
else:
self.add_line_operation_slot(idx, str(cur_time), str(cur_time+1), "", "插入旁白,推荐字数为0", "", self.projectContext.speaker_speed)
# self.add_line_operation_slot(idx, self.projectContext.all_elements[idx - 1].ed_time_sec, str(cur_time+1), "", "0/100", "", self.projectContext.speaker_speed)
self.add_line_operation_slot(idx, self.projectContext.all_elements[idx - 1].ed_time_sec, self.projectContext.all_elements[idx - 1].ed_time_sec, "", "0/100", "", self.projectContext.speaker_speed)
def calculate_element_row(self, cur_time: float):
"""确认表格中适合cur_time的插入位置
......@@ -1757,7 +2043,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""
idx = 0
while idx < len(self.projectContext.all_elements):
if float(cur_time) < float(self.projectContext.all_elements[idx].st_time_sec):
if float(cur_time) < float(utils.reverse_time_to_seconds(self.projectContext.all_elements[idx].st_time_sec)):
break
idx += 1
return idx
......@@ -1802,10 +2088,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
speed (str): 旁白语速
"""
# 注意,这里需要用同一对象,不能生成多个Element
# if end_time is None or end_time == "":
# print(">>>>>>>>>>>>add line")
# end_time = self.projectContext.all_elements[int(row)].st_time_sec
new_element = Element(start_time, end_time, subtitle, suggest, aside, speed)
new_element.print_self()
self.projectContext.all_elements.insert(int(row), new_element)
self.all_tableWidget_idx = int(row)
if suggest is not None and "插入旁白,推荐字数为" in suggest:
# if suggest is not None and "插入旁白,推荐字数为" in suggest:
if suggest is not None and suggest != "":
idx = 0
while idx < len(self.projectContext.aside_list):
if float(start_time) < float(self.projectContext.aside_list[idx].st_time_sec):
......@@ -1825,7 +2116,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.refresh_tab_slot()
self.prompt_dialog.show_with_msg("操作成功!!请查看变化")
def batch_add_line_operation_slot(self, elements):
def batch_add_line_operation_slot(self, elements, state, workerThread):
"""添加一行信息
Args:
......@@ -1839,21 +2130,32 @@ class MainWindow(QMainWindow, Ui_MainWindow):
"""
# 注意,这里需要用同一对象,不能生成多个Element
self.check_org_aside(elements)
print(">>>>>>>elements size")
print(len(elements))
total = len(elements)
index = 0
for new_element in elements:
index = index + 1
state[0] = index / total
start_time = new_element.st_time_sec
suggest = new_element.suggest
aside = new_element.aside
subtitle = new_element.subtitle
print(">>>>>>aside: " + aside)
print(start_time)
# insert_time = self.getSeconds(start_time)
# cur_time = round(insert_time/1000, 3)
row, same_flag = self.removeByCurTime(start_time, aside)
#该旁白没有被改动
# #该旁白没有被改动
if same_flag:
continue
# row = self.calculate_element_row(cur_time)
print(start_time)
row = self.calculate_element_row(float(start_time))
print(int(row))
self.projectContext.all_elements.insert(int(row), new_element)
self.all_tableWidget_idx = int(row)
if suggest is not None and "插入旁白,推荐字数为" in suggest:
# if suggest is not None and "插入旁白,推荐字数为" in suggest:
if suggest is not None and suggest != "":
idx = 0
while idx < len(self.projectContext.aside_list):
if float(start_time) == float(self.projectContext.aside_list[idx].st_time_sec) and aside != self.projectContext.aside_list[idx].aside:
......@@ -1864,7 +2166,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
idx += 1
self.projectContext.aside_list.insert(idx, new_element)
self.pb_tableWidget_idx = idx
self.do_generate_audio_by_aside_row(idx)
# self.do_generate_audio_by_aside_row(idx)
else:
idx = 0
while idx < len(self.projectContext.subtitle_list):
......@@ -1876,8 +2178,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
idx += 1
self.projectContext.subtitle_list.insert(idx, new_element)
self.zm_tableWidget_idx = idx
self.refresh_tab_slot()
self.prompt_dialog.show_with_msg("操作成功!!请查看变化")
# self.refresh_tab_slot()
time.sleep(1)
workerThread.refresh()
def check_org_aside(self, elements):
start_time_map = {}
......@@ -1896,18 +2200,21 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# self.projectContext.aside_list=new_list
# self.refresh_tab_slot(True)
for item in remove_list:
print(">>>>>remove")
item.print_self()
idx = 0
del_row = 0
while idx < len(self.projectContext.aside_list):
if item.st_time_sec == self.projectContext.aside_list[idx].st_time_sec:
self.projectContext.aside_list.pop(idx)
print(">>>>>>>>>>>> item sec")
print(item.st_time_sec)
del_row, _ = self.removeByCurTime(item.st_time_sec, item.aside, False)
break
idx += 1
self.pb_tableWidget_idx = idx
self.refresh_tab_slot()
self.del_line_operation_slot(row=(del_row + 1))
# self.refresh_tab_slot()
self.del_line_operation_slot(row=(del_row + 1),refresh_flag=False)
# for aside in self.projectContext.aside_list:
# if item.st_time_sec == aside.st_time_sec:
......@@ -1942,7 +2249,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
# 新的element
elem = Element(start_time, end_time, subtitle, suggest, aside, speed)
if suggest is not None and "插入旁白,推荐字数为" in suggest:
# if suggest is not None and "插入旁白,推荐字数为" in suggest:
if suggest is not None and suggest != "":
for i in range(len(self.projectContext.aside_list)):
if to_be_modify_element.equalTo(self.projectContext.aside_list[i]):
print(i)
......@@ -1966,7 +2274,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.prompt_dialog.show_with_msg("操作成功!!请查看变化")
# 只有row起作用
def del_line_operation_slot(self, row: int, start_time="0", end_time="0", subtitle="", suggest="", aside="", speed=""):
def del_line_operation_slot(self, row: int, start_time="0", end_time="0", subtitle="", suggest="", aside="", speed="", refresh_flag = True):
"""删除一行
Args:
......@@ -1979,8 +2287,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
speed (str, optional): 旁白语速. Defaults to "".
"""
to_be_delete_element = self.projectContext.all_elements[int(row) - 1]
# if self.projectContext.all_elements[int(row)-1].suggest is not None \
# and "插入旁白,推荐字数为" in self.projectContext.all_elements[int(row)-1].suggest:
if self.projectContext.all_elements[int(row)-1].suggest is not None \
and "插入旁白,推荐字数为" in self.projectContext.all_elements[int(row)-1].suggest:
and self.projectContext.all_elements[int(row)-1].suggest != "":
for i in range(len(self.projectContext.aside_list)):
if to_be_delete_element.equalTo(self.projectContext.aside_list[i]):
self.pb_tableWidget_idx = i
......@@ -2001,8 +2311,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.all_tableWidget_idx = int(row)-1
self.projectContext.all_elements.pop(int(row)-1)
self.refresh_tab_slot()
self.prompt_dialog.show_with_msg("操作成功!!请查看变化")
if refresh_flag:
self.refresh_tab_slot()
self.prompt_dialog.show_with_msg("操作成功!!请查看变化")
def pb_item_changed_by_double_clicked_slot(self, item):
"""双击后修改旁白文本
......@@ -2096,4 +2407,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.projectContext.all_elements[row])
self.projectContext.all_elements[int(all_idx)].speed = combo.currentText()
self.all_tableWidget.setItem(int(all_idx), constant.Content.SpeedColumnNumber, QTableWidgetItem(combo.currentText()))
self.do_generate_audio_by_aside_row_all(int(row))
\ No newline at end of file
self.do_generate_audio_by_aside_row_all(int(row))
def confirm_head_aside(self):
print(">>>>>>>>>>>>>confirm_head_aside")
position = self.sld_video.value()
video_position = int(
(position / self.sld_video.maximum()) * self.player.duration())
self.aside_head_time = utils.transfer_second_to_time(
str(round(video_position/1000, 2)))
self.import_excel_dialog.show_with_msg("定位成功:" + self.aside_head_time)
\ No newline at end of file
......@@ -11,28 +11,60 @@ from PyQt5.QtWidgets import QMainWindow, QFileDialog, QTableWidget, QTableWidget
from PyQt5.QtCore import QUrl, Qt, QTimer, QRect, pyqtSignal, QPersistentModelIndex
from PyQt5.QtMultimedia import *
from PyQt5.QtGui import QIcon, QPainter, QColor, QPen
import threading
lock = threading.Lock()
class MyWidget(QWidget):
# def __init__(self, parent=None):
# super(QWidget, self).__init__(parent)
# self.painter_flag = True
def paintEvent(self, event):
print(">>>>>>>>>>>>>>>into paint")
# print(">>>>>>>>into paint")
# print(self.painter_flag)
# if self.painter_flag:
lock.acquire()
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing) # Optional: Enable anti-aliasing
# painter.setCompositionMode(QPainter.CompositionMode_SourceOver) # Set composition mode
# # Draw existing content
# painter.fillRect(event.rect(), QColor(255, 255, 255)) # Fill with white color (you can adjust as needed)
# Draw a transparent horizontal line
painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
painter.drawLine(0, 1, 800, 1)
painter.end()
lock.release()
# self.painter_flag = False
# painter = QPainter(self)
# painter.setRenderHint(QPainter.Antialiasing) # Optional: Enable anti-aliasing
# # painter.setCompositionMode(QPainter.CompositionMode_SourceOver) # Set composition mode
# # # Draw existing content
# # painter.fillRect(event.rect(), QColor(255, 255, 255)) # Fill with white color (you can adjust as needed)
# # Draw a transparent horizontal line
# painter.setPen(QPen(Qt.gray, 2, Qt.SolidLine))
# painter.drawLine(0, 1, 800, 1)
# painter.end()
def change_painter_flag(self, state):
print(">>>>>>>>>>>>>>>change state")
# print(state)
# self.painter_flag = state
def up(self, mov_len):
print(">>>>>>>>>>>up" + str(mov_len))
self.move(0, self.y() - mov_len)
# painter = QPainter(self)
# painter.setRenderHint(QPainter.Antialiasing) # Optional: Enable anti-aliasing
# painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
# painter.drawLine(0, 1, 800, 1)
# painter.end()
return self.y()
def down(self, mov_len):
print(">>>>>>>>>>>down" + str(mov_len))
self.move(0,self.y() + mov_len)
# painter = QPainter(self)
# painter.setRenderHint(QPainter.Antialiasing) # Optional: Enable anti-aliasing
# painter.setPen(QPen(Qt.red, 2, Qt.SolidLine))
# painter.drawLine(0, 1, 800, 1)
# painter.end()
return self.y()
class Ui_MainWindow(object):
......@@ -178,8 +210,8 @@ class Ui_MainWindow(object):
"\n"
" QSlider::handle:horizontal {\n"
" image: url(res/images/slider.svg);\n"
" width: 12px;\n"
" height: 12px;\n"
" width: 18px;\n"
" height: 18px;\n"
" margin: -24px -12px;\n"
" }\n"
"\n"
......@@ -202,9 +234,70 @@ class Ui_MainWindow(object):
self.sld_audio.setOrientation(QtCore.Qt.Horizontal)
self.sld_audio.setObjectName("sld_audio")
self.horizontalLayout_5.addWidget(self.sld_audio)
self.pb_sld_audio = QtWidgets.QSlider(self.centralwidget)
self.pb_sld_audio.setMinimumSize(QtCore.QSize(0, 24))
self.pb_sld_audio.setMaximumSize(QtCore.QSize(80, 24))
self.pb_sld_audio.setProperty("value", 100)
self.pb_sld_audio.setStyleSheet("QSlider:horizontal {\n"
" min-height: 24px;\n"
" max-height: 24px;\n"
" }\n"
"\n"
" QSlider:vertical {\n"
" min-width: 24px;\n"
" max-width: 24px;\n"
" }\n"
"\n"
" QSlider::groove:horizontal {\n"
" height: 4px;\n"
" background: #393939;\n"
" margin: 0 12px;\n"
" }\n"
"\n"
" QSlider::groove:vertical {\n"
" width: 4px;\n"
" background: #393939;\n"
" margin: 12px 0;\n"
" border-radius: 24px;\n"
" }\n"
"\n"
" QSlider::handle:horizontal {\n"
" image: url(res/images/slider.svg);\n"
" width: 18px;\n"
" height: 18px;\n"
" margin: -24px -12px;\n"
" }\n"
"\n"
" QSlider::handle:vertical {\n"
" image: url(res/images/slider.svg);\n"
" border-radius: 24px;\n"
" width: 12px;\n"
" height: 12px;\n"
" margin: -12px -24px;\n"
" }\n"
"\n"
" QSlider::add-page {\n"
" background: #232629;\n"
" }\n"
"\n"
" QSlider::sub-page {\n"
" background: #ffd740;\n"
" }")
self.pb_sld_audio.setProperty("value", 99)
self.pb_sld_audio.setOrientation(QtCore.Qt.Horizontal)
self.pb_sld_audio.setObjectName("sld_audio")
self.lab_audio = QtWidgets.QLabel(self.centralwidget)
self.lab_audio.setObjectName("lab_audio")
self.horizontalLayout_5.addWidget(self.lab_audio)
self.horizontalLayout_5.addWidget(self.sld_audio)
self.horizontalLayout_5.addWidget(self.pb_sld_audio)
self.pb_audio = QtWidgets.QLabel(self.centralwidget)
self.pb_audio.setObjectName("pb_audio")
self.horizontalLayout_5.addWidget(self.pb_audio)
self.horizontalLayout_5.setStretch(0, 2)
self.horizontalLayout_5.setStretch(1, 1)
self.horizontalLayout_5.setStretch(3, 1)
......@@ -216,7 +309,34 @@ class Ui_MainWindow(object):
self.insert_aside_from_now_btn = QtWidgets.QPushButton(self.centralwidget)
self.insert_aside_from_now_btn.setObjectName("insert_aside_from_now_btn")
self.horizontalLayout_6.addWidget(self.insert_aside_from_now_btn)
self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
self.horizontalLayout_7.setObjectName("horizontalLayout_7")
self.up_ocr_btn = QtWidgets.QPushButton(self.centralwidget)
self.up_ocr_btn.setObjectName("up_ocr_btn")
self.horizontalLayout_7.addWidget(self.up_ocr_btn)
self.down_ocr_btn = QtWidgets.QPushButton(self.centralwidget)
self.down_ocr_btn.setObjectName("down_ocr_btn")
self.horizontalLayout_7.addWidget(self.down_ocr_btn)
self.up_ocr_bottom_btn = QtWidgets.QPushButton(self.centralwidget)
self.up_ocr_bottom_btn.setObjectName("up_ocr_bottom_btn")
self.horizontalLayout_7.addWidget(self.up_ocr_bottom_btn)
self.down_ocr_bottom_btn = QtWidgets.QPushButton(self.centralwidget)
self.down_ocr_bottom_btn.setObjectName("down_ocr_bottom_btn")
self.horizontalLayout_7.addWidget(self.down_ocr_bottom_btn)
self.confirm_head_aside_btn = QtWidgets.QPushButton(self.centralwidget)
self.confirm_head_aside_btn.setObjectName("confirm_head_aside_btn")
self.horizontalLayout_7.addWidget(self.confirm_head_aside_btn)
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
self.detect_btn = QtWidgets.QPushButton(self.centralwidget)
self.detect_btn.setObjectName("detect_btn")
self.horizontalLayout_8.addWidget(self.detect_btn)
self.verticalLayout_2.addLayout(self.horizontalLayout_6)
self.verticalLayout_2.addLayout(self.horizontalLayout_7)
self.verticalLayout_2.addLayout(self.horizontalLayout_8)
self.verticalLayout_2.setStretch(0, 8)
self.verticalLayout_2.setStretch(1, 1)
self.shuiping.addLayout(self.verticalLayout_2)
......@@ -241,6 +361,7 @@ class Ui_MainWindow(object):
self.all_tableWidget.setObjectName("all_tableWidget")
self.all_tableWidget.setColumnCount(0)
self.all_tableWidget.setRowCount(0)
# self.all_tableWidget.setStyleSheet(f"QTableWidget::item:selected:enabled {{ background-color: blue; color: white; }}")
self.all_tableWidget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.horizontalLayout_4.addWidget(self.all_tableWidget)
self.tabWidget.addTab(self.all_tab, "")
......@@ -302,6 +423,15 @@ class Ui_MainWindow(object):
self.sld_video.setTickPosition(QtWidgets.QSlider.TicksAbove)
self.sld_video.setTickInterval(1)
self.sld_video.setObjectName("sld_video")
# self.sld_video_pb = myVideoSlider(self.scrollAreaWidgetContents)
# self.sld_video_pb.setGeometry(QtCore.QRect(10, 20, 780, 30))
# self.sld_video_pb.setMinimumSize(QtCore.QSize(770, 0))
# self.sld_video_pb.setMaximumSize(QtCore.QSize(16777215, 20))
# self.sld_video_pb.setMaximum(100)
# self.sld_video_pb.setOrientation(QtCore.Qt.Horizontal)
# self.sld_video_pb.setTickPosition(QtWidgets.QSlider.TicksAbove)
# self.sld_video_pb.setTickInterval(1)
# self.sld_video_pb.setObjectName("sld_video_pb")
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.scrollArea.setGeometry(QtCore.QRect(0, 0, 820, 42))
self.zm_slider_layout.addWidget(self.scrollArea)
......@@ -357,6 +487,8 @@ class Ui_MainWindow(object):
self.menu.setObjectName("menu")
self.menu_2 = QtWidgets.QMenu(self.menubar)
self.menu_2.setObjectName("menu_2")
self.menu_7 = QtWidgets.QMenu(self.menubar)
self.menu_7.setObjectName("menu_7")
# self.menu_3 = QtWidgets.QMenu(self.menubar)
# self.menu_3.setObjectName("menu_3")
self.menu_4 = QtWidgets.QMenu(self.menubar)
......@@ -397,14 +529,16 @@ class Ui_MainWindow(object):
self.action_4.setEnabled(False)
self.action_5 = QtWidgets.QAction("旁白导入",self,triggered=self.import_excel)
self.action_5.setEnabled(False)
self.action_6 = QtWidgets.QAction("字幕上边界++",self,triggered=self.up_ocr)
self.action_6 = QtWidgets.QAction("字幕上边界上移",self,triggered=self.up_ocr)
self.action_6.setEnabled(True)
self.action_7 = QtWidgets.QAction("字幕上边界--",self,triggered=self.down_ocr)
self.action_7 = QtWidgets.QAction("字幕上边界下移",self,triggered=self.down_ocr)
self.action_7.setEnabled(True)
self.action_8 = QtWidgets.QAction("字幕下边界++",self,triggered=self.up_ocr_bottom)
self.action_8 = QtWidgets.QAction("字幕下边界上移",self,triggered=self.up_ocr_bottom)
self.action_8.setEnabled(True)
self.action_9 = QtWidgets.QAction("字幕下边界--",self,triggered=self.down_ocr_bottom)
self.action_9 = QtWidgets.QAction("字幕下边界下移",self,triggered=self.down_ocr_bottom)
self.action_9.setEnabled(True)
self.action_10 = QtWidgets.QAction("片头旁白定位",self,triggered=self.confirm_head_aside)
self.action_10.setEnabled(True)
# self.action_3.setObjectName("action_3")
# self.action_4 = QtWidgets.QAction(MainWindow)
......@@ -424,7 +558,7 @@ class Ui_MainWindow(object):
self.menu.addAction(self.action_create)
self.menu.addAction(self.action_open_project)
self.menu.addSeparator()
self.menu.addAction(self.import_movie)
# self.menu.addAction(self.import_movie)
self.menu.addAction(self.action_export)
self.menu.addSeparator()
self.menu.addAction(self.action_save)
......@@ -439,14 +573,17 @@ class Ui_MainWindow(object):
# self.menu_3.addAction(self.action_5)
# self.menu_3.addSeparator()
self.menubar.addAction(self.menu.menuAction())
self.menubar.addAction(self.menu_2.menuAction())
self.menubar.addAction(self.action_3)
# self.menubar.addAction(self.menu_2.menuAction())
# self.menubar.addAction(self.menu_7.menuAction())
# self.menubar.addAction(self.action_3)
self.menubar.addAction(self.action_4)
self.menubar.addAction(self.action_5)
self.menubar.addAction(self.action_6)
self.menubar.addAction(self.action_7)
self.menubar.addAction(self.action_8)
self.menubar.addAction(self.action_9)
self.menu_7.addAction(self.action_6)
self.menu_7.addAction(self.action_7)
self.menu_7.addAction(self.action_8)
self.menu_7.addAction(self.action_9)
self.menu_7.addAction(self.action_10)
# self.menubar.addAction(self.menu_5.menuAction())
# self.menubar.addAction(self.menu_6.menuAction())
# self.menubar.addAction(self.menu_3.menuAction())
......@@ -460,7 +597,14 @@ class Ui_MainWindow(object):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_2.setText(_translate("MainWindow", "00:00/00:00"))
self.lab_audio.setText(_translate("MainWindow", "音量:100%"))
self.pb_audio.setText(_translate("MainWindow", "旁白音量:100%"))
self.insert_aside_from_now_btn.setText(_translate("MainWindow", "当前位置插入旁白"))
self.up_ocr_btn.setText(_translate("MainWindow", "字幕上边界上移"))
self.down_ocr_btn.setText(_translate("MainWindow", "字幕上边界下移"))
self.up_ocr_bottom_btn.setText(_translate("MainWindow", "字幕下边界上移"))
self.down_ocr_bottom_btn.setText(_translate("MainWindow", "字幕下边界下移"))
self.confirm_head_aside_btn.setText(_translate("MainWindow", "片头旁白定位"))
self.detect_btn.setText(_translate("MainWindow", "旁白区间检测"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.all_tab), _translate("MainWindow", "字幕旁白"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.zm_tab), _translate("MainWindow", "字幕"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.pb_tab), _translate("MainWindow", "旁白"))
......@@ -469,12 +613,14 @@ class Ui_MainWindow(object):
self.pb_label.setText(_translate("MainWindow", "刻度"))
self.menu.setTitle(_translate("MainWindow", "文件"))
self.menu_2.setTitle(_translate("MainWindow", "编辑"))
self.menu_7.setTitle(_translate("MainWindow", "旁白检测准备"))
# self.menu_3.setTitle(_translate("MainWindow", "功能按键"))
self.menu_4.setTitle(_translate("MainWindow", "旁白区间检测"))
self.menu_5.setTitle(_translate("MainWindow", "旁白音频合成"))
self.menu_6.setTitle(_translate("MainWindow", "旁白导入"))
self.setting.setText(_translate("MainWindow", "设置"))
self.action_open_project.setText(_translate("MainWindow", "打开"))
# self.action_open_project.setText(_translate("MainWindow", "打开"))
self.action_open_project.setText(_translate("MainWindow", "加载"))
self.import_movie.setText(_translate("MainWindow", "视频导入"))
self.actions.setText(_translate("MainWindow", "内容导出"))
self.action_save.setText(_translate("MainWindow", "保存并备份"))
......
......@@ -9,7 +9,7 @@ import openpyxl
import constant
from openpyxl.styles import PatternFill, Alignment
from utils import replace_path_suffix, transfer_second_to_time
from utils import replace_path_suffix, transfer_second_to_time, reverse_time_to_seconds, get_seconds, transfer_second_to_all_time
from speech_synthesis import Speaker
class RunThread(threading.Thread):
"""复写线程类,用于解决主线程无法捕捉子线程中异常的问题
......@@ -125,8 +125,9 @@ class ProjectContext:
self.speaker_speed = None
self.duration = 0
# 一些常量
self.header = ["起始时间", "终止时间", "字幕", '建议', '解说脚本', "语速"]
self.write_header = ["起始时间", "起始时间(转换后)", "终止时间", "终止时间(转换后)", "字幕", '建议', '解说脚本', "语速"]
self.header = ["起始时间", "终止时间", "字幕", '建议旁白字数', '解说脚本', "语速"]
# self.write_header = ["起始时间", "起始时间(转换后)", "终止时间", "终止时间(转换后)", "字幕", '建议', '解说脚本', "语速"]
self.write_header = ["起始时间", "终止时间", "字幕", '建议旁白字数', '解说脚本', "语速"]
self.aside_header = ['起始时间', '推荐字数', '解说脚本',"语速", "预览音频"]
self.subtitle_header = ["起始时间", "终止时间", "字幕"]
......@@ -185,7 +186,7 @@ class ProjectContext:
self.excel_path = info["excel_path"]
self.speaker_info = info["speaker_info"]["speaker_id"]
self.speaker_speed = info["speaker_info"]["speaker_speed"]
self.speaker_type = info["speaker_info"]["speaker_type"] if "speaker_type" in info["speaker_info"] else "科大讯飞"
self.speaker_type = info["speaker_info"]["speaker_type"] if "speaker_type" in info["speaker_info"] else "浙大内部tts"
self.detected = info["detection_info"]["detected"]
self.nd_process = info["detection_info"]["nd_process"]
self.last_time = info["detection_info"]["last_time"]
......@@ -231,7 +232,6 @@ class ProjectContext:
# 先备份文件,再覆盖主文件,可选是否需要备份,默认需要备份
# 20221030:添加旁白检测的进度
def save_project(self, need_save_new: bool=False) -> str:
print("22222sava")
self.save_conf()
# all_element = sorted(all_element, key=lambda x: float(x.st_time_sec))
print("current excel_path:", self.excel_path)
......@@ -260,7 +260,7 @@ class ProjectContext:
def refresh_element(self, row, aside: str):
self.all_elements[int(row)].aside = aside
if not self.initial_ing:
if not self.initial_ing:
save_excel_to_path(self.all_elements, self.excel_path, self.write_header, self.excel_sheet_name)
def refresh_speed(self, row, speed: str)->None:
......@@ -279,8 +279,16 @@ class ProjectContext:
# todo:现在是只用None判断是否是字幕,后续是否也需要用""来?
for i in range(len(d["字幕"])):
st_time_sec, ed_time_sec, subtitle, suggest, aside, speed = [d[x][i] for x in self.header]
print(">>>>>>>>>>>>>>load ed time")
print(st_time_sec)
print(ed_time_sec)
if ed_time_sec == None or ed_time_sec == "":
print(">>>>into load")
ed_time_sec = st_time_sec
# 当前条目是字幕
if d["字幕"][i] != None:
st_time_sec = reverse_time_to_seconds(str(st_time_sec))
ed_time_sec = reverse_time_to_seconds(str(ed_time_sec))
self.subtitle_list.append(Element(st_time_sec, ed_time_sec, subtitle, suggest, aside, speed))
self.all_elements.append(self.subtitle_list[-1])
else:
......@@ -299,12 +307,22 @@ class ProjectContext:
if d["终止时间"][i] is None:
# 如果是最后一条
if i == len(d["字幕"]) - 1:
ed_time_sec = "360000" if self.duration == 0 else self.duration # todo 默认最大时长是100h
print(1)
# ed_time_sec = "360000" if self.duration == 0 else self.duration # todo 默认最大时长是100h
else:
ed_time_sec = "%.2f"%(float(d["起始时间"][i + 1]) - 0.01)
else:
ed_time_sec = d["终止时间"][i]
st_time_sec = reverse_time_to_seconds(str(st_time_sec))
ed_time_sec = reverse_time_to_seconds(str(ed_time_sec))
if aside == None:
aside = ""
if suggest != None and suggest != "":
arrays = suggest.split("/")
if len(arrays) == 2:
suggest = str(len(aside)) + "/" + arrays[1]
else:
suggest = str(len(aside)) + "/" + arrays[0]
self.aside_list.append(Element(st_time_sec, ed_time_sec, subtitle, suggest, aside, speed))
self.all_elements.append(self.aside_list[-1])
# print("[load_excel_from_path] ", end='')
......@@ -370,8 +388,9 @@ class ProjectContext:
for speaker in content["speaker_zju_details"]:
speaker_name.append(
",".join([speaker["name"], speaker["gender"], speaker["age_group"]]))
if self.speaker_info is None:
if self.speaker_info is None or self.speaker_info == "":
self.speaker_info = speaker_name[0]
print(">>>>>>>>>>>>>>>>>get all info :" + self.speaker_info)
return tuple(speaker_name)
def init_speakers(self):
......@@ -450,17 +469,31 @@ def write_to_sheet(path: str, sheet_name: str, valuelist: list):
value = value_element.to_list()
# 把None换成空串
value = ["" if x == None else x for x in value]
value.insert(1, transfer_second_to_time(value[0])) if value[0] != "" else value.insert(1, "")
value.insert(3, transfer_second_to_time(value[2])) if value[2] != "" else value.insert(3, "")
# value.insert(1, transfer_second_to_time(value[0])) if value[0] != "" else value.insert(1, "")
# value.insert(3, transfer_second_to_time(value[2])) if value[2] != "" else value.insert(3, "")
# value[0] = get_seconds(value[0]) if value[0] != "" else ""
# value[1] = get_seconds(value[1]) if value[1] != "" else ""
value[0] = transfer_second_to_all_time(value[0]) if value[0] != "" else ""
value[1] = transfer_second_to_all_time(value[1]) if value[1] != "" else ""
suggest = value[3]
if suggest != None and suggest != "":
arrays = suggest.split("/")
if len(arrays) == 2:
value[3] = str(len(value[4])) + "/" + arrays[1]
else:
value[3] = str(len(value[4])) + "/" + arrays[0]
index = len(value)
cur_row = sheet.max_row
for j in range(0, index):
sheet.cell(row=cur_row + 1, column=j + 1, value=str(value[j]))
cell = sheet.cell(row=cur_row + 1, column=j + 1, value=str(value[j]))
if value[j] == '' or '插入旁白' in str(value[j]):
sheet.cell(row=cur_row + 1, column=j + 1).fill = PatternFill(fill_type='solid', fgColor='ffff00')
cell = sheet.cell(row=cur_row + 1, column=j + 1).fill = PatternFill(fill_type='solid', fgColor='ffff00')
if j == 4:
sheet.cell(row=cur_row + 1, column=j + 1).alignment = Alignment(wrapText=True)
cell = sheet.cell(row=cur_row + 1, column=j + 1).alignment = Alignment(wrapText=True)
cell.number_format = '@'
workbook.save(path)
......
......@@ -13,3 +13,4 @@ class myVideoSlider(QSlider):
# self.setValue(int(value)/9)
value = round(value/self.width()*self.maximum()) # 根据鼠标点击的位置和slider的长度算出百分比
self.ClickedValue.emit(value)
self.setFocus()
\ No newline at end of file
import re
import csv
import argparse
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from difflib import SequenceMatcher
title = ['起始时间(转换后)', '终止时间(转换后)', '字幕']
def init():
# 获取中文停用词列表
global stop_words
with open('chinese_stopwords.txt', 'r', encoding='utf-8') as file:
stop_words = set(line.strip() for line in file)
# 将保存的时间戳转化为秒
def change_to_second(time_str):
from datetime import datetime
time_obj = datetime.strptime(time_str, "%H:%M:%S,%f")
seconds = time_obj.hour * 3600 + time_obj.minute * 60 + \
time_obj.second + time_obj.microsecond / 1000000
return seconds
# 计算字幕的相似度
def calculate_similarity(str1, str2, method='cosine'):
if method == 'cosine':
tfidf_vectorizer = TfidfVectorizer()
tfidf_matrix = tfidf_vectorizer.fit_transform([str1, str2])
similarity_matrix = cosine_similarity(tfidf_matrix)
return similarity_matrix[0][1]
else :
return SequenceMatcher(None, str1, str2).ratio()
# 计算两个时间戳的时间差(单位:秒)
def calculate_time_difference(time1, time2):
return abs(time2 - time1)
def calculate_weight(x, y):
# weight = e^(-alpha * time_diff)
# 相差1s的系数为0.9
alpha = 0.11
return 1 / (alpha * (x + y) + 1)
# 检查句子中的每个单词是否都是停用词
def is_all_stopwords(sentence):
return all(word in stop_words for word in sentence)
### 如果其中有-符号,可能在用excel打开时自动添加=变成公式,读取的时候没问题
def read_srt_to_csv(path_srt, path_output):
with open(path_srt, 'r', encoding='utf-8-sig') as f:
srt_content = f.read() # str
# 使用正则表达式匹配时间码和字幕内容
pattern = re.compile(r'(\d+)\n([\d:,]+) --> ([\d:,]+)\n(.+?)(?=\n\d+\n|$)', re.DOTALL)
matches = pattern.findall(srt_content)
# 写入 csv 文件
with open(path_output, 'w', newline='', encoding='utf-8') as f:
csv_writer = csv.writer(f)
csv_writer.writerow(title)
for _, start, end, subtitle in matches: # 都是str格式
subtitle = re.sub(r'\{[^}]*\}', '', subtitle) # 将srt文件前的加粗等格式去掉
csv_writer.writerow([start, end, subtitle.strip()])
def read_from_xlsx(path_xlsx='output.xlsx', path_output='deal.csv'):
data = pd.read_excel(path_xlsx)
with open(path_output, 'w', newline='', encoding='utf-8') as f:
csv_writer = csv.writer(f)
csv_writer.writerow(title)
for _, data1 in data.iterrows():
start, end, subtitle = data1[1], data1[3], data1[4]
if isinstance(subtitle, float) and np.isnan(subtitle):
continue
# 与srt文件格式同步
start = start.replace('.', ',')
end = end.replace('.', ',')
# print(start, end, subtitle,)
# print(type(start), type(end), type(subtitle))
csv_writer.writerow([start, end, subtitle.strip()])
### 对于srt中的字幕计算相似性度。从ocr中找到时间戳满足<=time_t的字幕,
### 然后计算字幕间的相似度,取一个最大的。字幕从start和end都匹配一遍
# time_threshold设置阈值,用于判断时间差是否可接受
def measure_score(path_srt, path_ocr, time_threshold=5.0, method='cosine'):
data_srt, data_ocr = [], []
with open(path_srt, 'r', encoding='utf-8') as file:
csv_reader = csv.reader(file)
data_srt = [i for i in csv_reader]
data_srt.pop(0)
for i in range(len(data_srt)):
data_srt[i][0] = change_to_second(data_srt[i][0])
data_srt[i][1] = change_to_second(data_srt[i][1])
with open(path_ocr, 'r', encoding='utf-8') as file:
csv_reader = csv.reader(file)
data_ocr = [i for i in csv_reader]
data_ocr.pop(0)
for i in range(len(data_ocr)):
data_ocr[i][0] = change_to_second(data_ocr[i][0])
data_ocr[i][1] = change_to_second(data_ocr[i][1])
# 计算相似度
total_similarity = 0.0
total_weight = 0.0
for sub in data_srt:
max_similarity = 0.0
# 去除srt中的停用词
if is_all_stopwords(sub[2]):
continue
for sub1 in data_ocr:
x, y = abs(sub[0] - sub1[0]), abs(sub[1] - sub1[1])
if min(x, y) <= time_threshold:
# print(sub[2], sub1[2])
score = calculate_similarity(sub[2], sub1[2], 'cosine')
max_similarity = max(max_similarity, score * calculate_weight(x, y))
total_similarity += max_similarity
total_weight += 1
# print(total_similarity, total_similarity / len(data_srt), total_similarity / total_weight)
return total_similarity / len(data_srt), total_similarity / total_weight
if __name__ == '__main__':
init()
parser = argparse.ArgumentParser(description="benchmark")
# 添加命令行参数
parser.add_argument("--path_srt", required=True, type=str, help="Path of srt file, format is srt")
parser.add_argument("--path_ocr", required=True, type=str, help="Path of ocr file, format is xlsx")
parser.add_argument("--method", type=str, default='cosine', help="Select evaluation method")
parser.add_argument("--time_threshold", type=float,default=5.0, help="Allowable time frame")
args = parser.parse_args()
output_file_srt = 'deal_srt.csv'
output_file_ocr = 'deal_ocr.csv'
read_srt_to_csv(args.path_srt, output_file_srt)
read_from_xlsx(args.path_ocr, output_file_ocr)
score = measure_score(output_file_srt, output_file_ocr, args.time_threshold, args.method)
print(f'该评估算法得分: {score[1]:.5f}')
\ No newline at end of file
......@@ -260,9 +260,12 @@ class Operation_Dialog(QDialog, Ui_Dialog):
else: # 如果是旁白
end_time = ""
subtitle = ""
suggest = "插入旁白,推荐字数为" + suggest
# suggest = "插入旁白,推荐字数为" + suggest
# if self.comboBox_2.currentText() == "增加一行":
# suggest = "插入旁白,推荐字数为0"
suggest = suggest
if self.comboBox_2.currentText() == "增加一行":
suggest = "插入旁白,推荐字数为0"
suggest = "0/100"
# 别忘复原
self.buttonBox.setEnabled(False)
self.zmpb_change_slot()
......
......@@ -14,6 +14,7 @@ from PyQt5.QtWidgets import *;
from management import RunThread
from speech_synthesis import ffmpeg_path
from ffmpeg_util import cg_wav
class ExportProcessor(QWidget):
show_warning_signal = pyqtSignal(str)
......@@ -23,27 +24,30 @@ class ExportProcessor(QWidget):
self.state = [0]
self.threads = []
def export_slot(self, video_path, output_dir):
def export_slot(self, video_path, output_dir, pb_cg_rate):
t = RunThread(funcName=self.start_export,
args=(video_path, output_dir),
args=(video_path, output_dir, pb_cg_rate),
name="export")
t.setDaemon(True)
self.threads.append(t)
for t in self.threads:
t.start()
try:
t.start()
except Exception as e:
print(e)
print("===子线程已经开启 in export===")
self.export_callback_signal.emit(self.threads, self.state)
def start_export(self, video_path, output_dir):
mixed_audio_path = aggrevate_audios(video_path, output_dir, self.state)
def start_export(self, video_path, output_dir, pb_cg_rate):
mixed_audio_path = aggrevate_audios(video_path, output_dir, self.state, pb_cg_rate)
export_video(video_path, mixed_audio_path, output_dir, self.state)
# 生成一条无声的音频,然后把旁白音频逐个按照时间位置放进去,得到仅含旁白的音频和旁白+原声的音频
def aggrevate_audios(video_path: str, output_dir: str, state=None):
def aggrevate_audios(video_path: str, output_dir: str, state=None,pb_cg_rate = 1.00):
# 这个模块最多只有80%的进度
if state is None:
state = [0]
......@@ -56,6 +60,18 @@ def aggrevate_audios(video_path: str, output_dir: str, state=None):
# 将生成的旁白音频放入空白音频中,并将原音频的对应位置音量降低为原来的30%
files = os.listdir(output_dir)
if pb_cg_rate != 1.00:
audio_path = os.path.join(output_dir, os.path.basename(video_path).split('.')[0] + ".wav")
for i, f in enumerate(files):
fname = '.'.join(f.split('.')[:-1])
try:
if fname.find(".") != -1:
cg_wav(audio_path, os.path.join(output_dir, f), pb_cg_rate)
except Exception as e:
print(e)
continue
for i, f in enumerate(files):
fname = '.'.join(f.split('.')[:-1])
try:
......
{"video_path": null, "excel_path": null, "detection_info": {"detected": false, "nd_process": 0.0, "last_time": 0.0, "caption_boundings": [], "has_subtitle": true}, "speaker_info": {"speaker_type": "\u6d59\u5927\u5185\u90e8tts", "speaker_id": "test\uff0c\u5973\uff0c\u5e74\u8f7b\u4eba", "speaker_speed": "1.00(4\u5b57/\u79d2)"}}
\ No newline at end of file
{"video_path": null, "excel_path": null, "detection_info": {"detected": false, "nd_process": 0.0, "last_time": 0.0, "caption_boundings": [], "has_subtitle": true}, "speaker_info": {"speaker_type": "", "speaker_id": "eagle\uff0c\u5973\uff0c\u5e74\u8f7b\u4eba", "speaker_speed": "1.00(4\u5b57/\u79d2)"}}
\ No newline at end of file
{
"speaker_details": [{
"id": 0,
"name": "晓辰",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "休闲、放松的语音,用于自发性对话和会议听录。",
"audio_path": "./res/speaker_audio/Xiaochen.wav",
"speaker_code": "zh-CN-XiaochenNeural"
},
{
"id": 1,
"name": "晓涵",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "温暖、甜美、富有感情的声音,可用于许多对话场景。",
"audio_path": "./res/speaker_audio/Xiaohan.wav",
"speaker_code": "zh-CN-XiaohanNeural"
},
{
"id": 2,
"name": "晓墨",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "清晰、放松的声音,具有丰富的角色扮演和情感,适合音频书籍。",
"audio_path": "./res/speaker_audio/Xiaomo.wav",
"speaker_code": "zh-CN-XiaomoNeural"
},
{
"id": 7,
"name": "晓晓",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "活泼、温暖的声音,具有多种场景风格和情感。",
"audio_path": "./res/speaker_audio/Xiaoxiao.wav",
"speaker_code": "zh-CN-XiaoxiaoNeural"
},
{
"id": 8,
"name": "晓萱",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "自信、有能力的声音,具有丰富的角色扮演和情感,适合音频书籍。",
"audio_path": "./res/speaker_audio/Xiaoxuan.wav",
"speaker_code": "zh-CN-XiaoxuanNeural"
},
{
"id": 9,
"name": "晓颜",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
"description": "训练有素、舒适的语音,用于客户服务和对话场景。",
"audio_path": "./res/speaker_audio/Xiaoyan.wav",
"speaker_code": "zh-CN-XiaoyanNeural"
},
{
"id": 3,
"name": "晓秋",
"language": "中文(普通话,简体)",
"age_group": "中年人",
"gender": "女",
"description": "智能、舒适的语音,适合阅读长内容。",
"audio_path": "./res/speaker_audio/Xiaoqiu.wav",
"speaker_code": "zh-CN-XiaoqiuNeural"
},
{
"id": 4,
"name": "晓秋",
"language": "中文(普通话,简体)",
"age_group": "中年人",
"gender": "女",
"description": "智能、舒适的语音,适合阅读长内容。",
"audio_path": "./res/speaker_audio/Xiaoqiu.wav",
"speaker_code": "zh-CN-XiaoqiuNeural"
},
{
"id": 5,
"name": "晓睿",
"language": "中文(普通话,简体)",
"age_group": "老年",
"gender": "女",
"description": "成熟、睿智的声音,具有丰富的情感,适合音频书籍。",
"audio_path": "./res/speaker_audio/Xiaorui.wav",
"speaker_code": "zh-CN-XiaoruiNeural"
},
{
"id": 6,
"name": "晓双",
"language": "中文(普通话,简体)",
"age_group": "儿童",
"gender": "女",
"description": "可爱、愉悦的语音,可应用于许多儿童相关场景。",
"audio_path": "./res/speaker_audio/Xiaoshuang.wav",
"speaker_code": "zh-CN-XiaoshuangNeural"
},
{
"id": 10,
"name": "晓悠",
"language": "中文(普通话,简体)",
"age_group": "儿童",
"gender": "女",
"description": "天使般的清晰声音,可以应用于许多儿童相关场景。",
"audio_path": "./res/speaker_audio/Xiaoyou.wav",
"speaker_code": "zh-CN-XiaoyouNeural"
},
{
"id": 11,
"name": "云希",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "男",
"description": "活泼、阳光的声音,具有丰富的情感,可用于许多对话场景。",
"audio_path": "./res/speaker_audio/Yunxi.wav",
"speaker_code": "zh-CN-YunxiNeural"
},
{
"id": 12,
"name": "云扬",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "男",
"description": "专业、流利的声音,具有多种场景风格。",
"audio_path": "./res/speaker_audio/Yunyang.wav",
"speaker_code": "zh-CN-YunyangNeural"
},
{
"id": 13,
"name": "云野",
"language": "中文(普通话,简体)",
"age_group": "中年人",
"gender": "男",
"description": "成熟、放松的声音,具有多种情感,适合音频书籍。",
"audio_path": "./res/speaker_audio/Yunye.wav",
"speaker_code": "zh-CN-YunyeNeural"
}
"speaker_details": [
],
"speaker_zju_details": [{
"id": 0,
"name": "test",
"name": "eagle",
"language": "中文(普通话,简体)",
"age_group": "年轻人",
"gender": "女",
......
......@@ -39,6 +39,7 @@ class Setting_Dialog(QDialog, Ui_Dialog):
self.comboBox_2.clear()
# todo 把所有说话人都加上来
self.speaker_li = projectContext.get_all_speaker_info()
# self.speaker_li = []
self.speaker_zju_li = projectContext.get_all_speaker_zju_info() #本地tts
self.speed_list_zju = ["1.00(4字/秒)", "1.10(4.5字/秒)", "1.25(5字/秒)", "1.50(6字/秒)", "1.75(7字/秒)", "2.00(8字/秒)", "2.50(10字/秒)"] #本地tts
......@@ -46,7 +47,8 @@ class Setting_Dialog(QDialog, Ui_Dialog):
# self.comboBox.addItem(i)
self.speed_li_2 = ["1.00(4字/秒)", "1.10(4.5字/秒)", "1.25(5字/秒)", "1.50(6字/秒)", "1.75(7字/秒)", "2.00(8字/秒)", "2.50(10字/秒)"]
# self.comboBox_2.addItems(self.speed_li_2)
self.speaker_types = ["科大讯飞", "浙大内部tts"]
# self.speaker_types = ["科大讯飞", "浙大内部tts"]
self.speaker_types = ["浙大内部tts"]
self.comboBox_0.addItems(self.speaker_types)
print(projectContext.speaker_type)
if projectContext.speaker_type is None or projectContext.speaker_type == "":
......@@ -54,7 +56,7 @@ class Setting_Dialog(QDialog, Ui_Dialog):
else:
self.comboBox_0.setCurrentIndex(self.speaker_types.index(projectContext.speaker_type))
if self.comboBox_0.currentIndex() ==0: #讯飞
if self.comboBox_0.currentIndex() !=0: #讯飞
self.comboBox.addItems(self.speaker_li)
self.comboBox_2.addItems(self.speed_li_2)
else:
......@@ -67,13 +69,13 @@ class Setting_Dialog(QDialog, Ui_Dialog):
self.comboBox.setCurrentIndex(0)
else:
print(projectContext.speaker_info)
self.comboBox.setCurrentIndex(self.speaker_li.index(projectContext.speaker_info) if self.comboBox_0.currentIndex() ==0 else self.speaker_zju_li.index(projectContext.speaker_info))
self.comboBox.setCurrentIndex(self.speaker_li.index(projectContext.speaker_info) if self.comboBox_0.currentIndex() !=0 else self.speaker_zju_li.index(projectContext.speaker_info))
print(projectContext.speaker_speed)
if projectContext.speaker_speed is None or projectContext.speaker_speed == "":
self.comboBox_2.setCurrentIndex(0)
else:
self.comboBox_2.setCurrentIndex(self.speed_li_2.index(projectContext.speaker_speed) if self.comboBox_0.currentIndex() ==0 else self.speed_list_zju.index(projectContext.speaker_speed))
self.comboBox_2.setCurrentIndex(self.speed_li_2.index(projectContext.speaker_speed) if self.comboBox_0.currentIndex() !=0 else self.speed_list_zju.index(projectContext.speaker_speed))
finally:
self.refresh_flag = False
......@@ -84,7 +86,8 @@ class Setting_Dialog(QDialog, Ui_Dialog):
self.comboBox.clear()
self.comboBox_2.clear()
self.projectContext.speaker_type = self.comboBox_0.currentText()
if self.comboBox_0.currentIndex() ==0:
# if self.comboBox_0.currentIndex() ==0:
if self.comboBox_0.currentIndex() !=0:
print("讯飞")
self.comboBox.addItems(self.speaker_li)
self.comboBox_2.addItems(self.speed_li_2)
......@@ -106,12 +109,12 @@ class Setting_Dialog(QDialog, Ui_Dialog):
if self.projectContext.speaker_info is None or self.projectContext.speaker_info == "" :
self.comboBox.setCurrentIndex(0)
else:
self.comboBox.setCurrentIndex(self.speaker_li.index(self.projectContext.speaker_info) if self.comboBox_0.currentIndex() ==0 else self.speaker_zju_li.index(self.projectContext.speaker_info))
self.comboBox.setCurrentIndex(self.speaker_li.index(self.projectContext.speaker_info) if self.comboBox_0.currentIndex() !=0 else self.speaker_zju_li.index(self.projectContext.speaker_info))
if self.projectContext.speaker_speed is None or self.projectContext.speaker_speed == "":
self.comboBox_2.setCurrentIndex(0)
else:
self.comboBox_2.setCurrentIndex(self.speed_li_2.index(self.projectContext.speaker_speed) if self.comboBox_0.currentIndex() ==0 else self.speed_list_zju.index(self.projectContext.speaker_speed))
self.comboBox_2.setCurrentIndex(self.speed_li_2.index(self.projectContext.speaker_speed) if self.comboBox_0.currentIndex() !=0 else self.speed_list_zju.index(self.projectContext.speaker_speed))
def speaker_change_slot(self):
"""切换说话人
......
......@@ -23,11 +23,12 @@ from typing import Tuple
import datetime
import numpy as np
from azure.cognitiveservices.speech import SpeechConfig, SpeechSynthesizer, ResultReason, AudioDataStream
from azure.cognitiveservices.speech.audio import AudioOutputConfig
# from azure.cognitiveservices.speech import SpeechConfig, SpeechSynthesizer, ResultReason, AudioDataStream
# from azure.cognitiveservices.speech.audio import AudioOutputConfig
import openpyxl
import shutil
from vits_chinese import tts
from utils import reverse_time_to_seconds
tmp_file = 'tmp.wav'
adjusted_wav_path = "adjusted.wav"
......@@ -81,8 +82,11 @@ def choose_speaker(speaker_name: str) -> Speaker:
Returns:
Speaker: 返回对应说话人,如果没有这个说话人则报错
"""
print(">>>>>>>>>>>>>speakerName:" + speaker_name)
for speaker in speakers:
print(">>>>>>>>>>>>>speaker:" + speaker.name)
if speaker.name == speaker_name:
return speaker
raise ValueError
......@@ -105,41 +109,42 @@ def speech_synthesis(text: str, output_file: str, speaker: Speaker, speed: float
if speaker.speaker_type != None and speaker.speaker_type == "1":
tts(text, speed, output_file)
else:
speech_config = SpeechConfig(
subscription="db34d38d2d3447d482e0f977c66bd624",
region="eastus"
)
print("1")
# speech_config = SpeechConfig(
# subscription="db34d38d2d3447d482e0f977c66bd624",
# region="eastus"
# )
speech_config.speech_synthesis_language = "zh-CN"
speech_config.speech_synthesis_voice_name = speaker.speaker_code
# speech_config.speech_synthesis_language = "zh-CN"
# speech_config.speech_synthesis_voice_name = speaker.speaker_code
# 先把合成的语音文件输出得到tmp.wav中,便于可能的调速需求
# # 先把合成的语音文件输出得到tmp.wav中,便于可能的调速需求
synthesizer = SpeechSynthesizer(speech_config=speech_config, audio_config=None)
ssml_string = f"""
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="{speech_config.speech_synthesis_language}">
<voice name="{speaker.speaker_code}">
<prosody rate="{round((speed - 1.0) * 100, 2)}%">
{text}
</prosody>
</voice>
</speak>"""
result = synthesizer.speak_ssml_async(ssml_string).get()
stream = AudioDataStream(result)
stream.save_to_wav_file(output_file)
print(result.reason)
while result.reason == ResultReason.Canceled:
cancellation_details = result.cancellation_details
print("取消的原因", cancellation_details.reason, cancellation_details.error_details)
time.sleep(1)
synthesizer.stop_speaking()
del synthesizer
synthesizer = SpeechSynthesizer(speech_config=speech_config, audio_config=None)
result = synthesizer.speak_ssml_async(ssml_string).get()
stream = AudioDataStream(result)
stream.save_to_wav_file(output_file)
print(result.reason)
# synthesizer = SpeechSynthesizer(speech_config=speech_config, audio_config=None)
# ssml_string = f"""
# <speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis" xml:lang="{speech_config.speech_synthesis_language}">
# <voice name="{speaker.speaker_code}">
# <prosody rate="{round((speed - 1.0) * 100, 2)}%">
# {text}
# </prosody>
# </voice>
# </speak>"""
# result = synthesizer.speak_ssml_async(ssml_string).get()
# stream = AudioDataStream(result)
# stream.save_to_wav_file(output_file)
# print(result.reason)
# while result.reason == ResultReason.Canceled:
# cancellation_details = result.cancellation_details
# print("取消的原因", cancellation_details.reason, cancellation_details.error_details)
# time.sleep(1)
# synthesizer.stop_speaking()
# del synthesizer
# synthesizer = SpeechSynthesizer(speech_config=speech_config, audio_config=None)
# result = synthesizer.speak_ssml_async(ssml_string).get()
# stream = AudioDataStream(result)
# stream.save_to_wav_file(output_file)
# print(result.reason)
# detached
def change_speed_and_volume(wav_path: str, speed: float = 1.0):
......@@ -205,7 +210,7 @@ def get_narratage_text(sheet_content: dict) -> Tuple[list, list, list]:
for i, text in enumerate(narratage):
# 这里的speed是x.x倍速
speed = float(speeds[i].split('(')[0])
if text is not None:
if text is not None and text != "":
if text == '翻译':
narratage_text.append(subtitle[i])
else:
......@@ -236,8 +241,10 @@ def get_narratage_text(sheet_content: dict) -> Tuple[list, list, list]:
# narratage_start_time.append(cur_start)
# narratage_end_time.append(cur_end)
# cur_start = cur_start + (len(x) / normal_speed + normal_interval) / speed
narratage_start_time.append(float(start_time[i]))
narratage_end_time.append(float(end_time[i])) if end_time[i] is not None else narratage_end_time.append(-1)
# narratage_start_time.append(float(start_time[i]))
# narratage_end_time.append(float(end_time[i])) if end_time[i] is not None else narratage_end_time.append(-1)
narratage_start_time.append(float(reverse_time_to_seconds(start_time[i])))
narratage_end_time.append(float(reverse_time_to_seconds(end_time[i]))) if end_time[i] is not None and end_time[i] != "" else narratage_end_time.append(-1)
narratage_speed.append(speed)
return narratage_text, narratage_start_time, narratage_end_time, narratage_speed
......@@ -251,13 +258,16 @@ def second_to_str(seconds: float) -> str:
Returns:
str: “时:分:秒”格式的时间字符串
"""
seconds = float(seconds)
hour = int(seconds / 3600)
minute = int((seconds - hour * 3600) / 60)
second = int(seconds - hour * 3600 - minute * 60)
ms = int((seconds - second - minute * 60 - hour * 3600) * 1000)
time_str = "%02d:%02d:%02d,%03d" % (hour, minute, second, ms)
return time_str
try:
seconds = float(seconds)
hour = int(seconds / 3600)
minute = int((seconds - hour * 3600) / 60)
second = int(seconds - hour * 3600 - minute * 60)
ms = int((seconds - second - minute * 60 - hour * 3600) * 1000)
time_str = "%02d:%02d:%02d,%03d" % (hour, minute, second, ms)
return time_str
except:
return str(seconds)
def export_caption(sheet_content: dict, caption_file: str):
......
......@@ -56,19 +56,34 @@ def change_project_path(path):
if __name__ == '__main__':
try:
# subprocess.call(['deploy.bat'])
if not is_lav_filters_installed() or not is_file_copyed():
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./res/images/eagle_2.ico"))
apply_stylesheet(app, theme='dark_amber.xml')
mainWindow = MainWindow(project_path)
QtWidgets.QMessageBox.critical(mainWindow,'警告','视频解码器未正常安装',QtWidgets.QMessageBox.Yes)
else:
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
currentExitCode = MainWindow.EXIT_CODE_REBOOT
# if not is_lav_filters_installed() or not is_file_copyed():
# QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
# QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
# app = QApplication(sys.argv)
# app.setWindowIcon(QIcon("./res/images/eagle_2.ico"))
# apply_stylesheet(app, theme='dark_amber.xml')
# mainWindow = MainWindow(project_path)
# QtWidgets.QMessageBox.critical(mainWindow,'警告','视频解码器未正常安装',QtWidgets.QMessageBox.Yes)
# else:
# QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
# QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
# currentExitCode = MainWindow.EXIT_CODE_REBOOT
# if not os.path.exists("C:\LavFilters") and not os.path.exists("C:\Program Files (x86)\LAV Filters"):
# QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
# QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
# app = QApplication(sys.argv)
# app.setWindowIcon(QIcon("./res/images/eagle_2.ico"))
# apply_stylesheet(app, theme='dark_amber.xml')
# mainWindow = MainWindow(project_path)
# QtWidgets.QMessageBox.critical(mainWindow,'警告','视频解码器未正常安装',QtWidgets.QMessageBox.Yes)
# else:
# QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
# QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
# currentExitCode = MainWindow.EXIT_CODE_REBOOT
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
currentExitCode = MainWindow.EXIT_CODE_REBOOT
while currentExitCode == MainWindow.EXIT_CODE_REBOOT:
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./res/images/eagle_2.ico"))
......@@ -82,6 +97,8 @@ if __name__ == '__main__':
apply_stylesheet(app, theme='dark_amber.xml')
# mainWindow.show()
mainWindow.showMaximized()
if not os.path.exists("C:\LavFilters") and not os.path.exists("C:\Program Files (x86)\LAV Filters"):
mainWindow.import_excel_dialog.show_with_msg("视频解码器未正常安装")
currentExitCode = app.exec_()
app = None
except Exception as e:
......
......@@ -3,7 +3,7 @@
block_cipher = None
env_dir = 'C:/Users/AIA/.conda/envs/testmovie/Lib/site-packages/'
missingPkgs = ['Microsoft.CognitiveServices.Speech.core.dll', 'decorator.py', 'google', 'paddle', 'paddleocr', 'PIL', 'requests', 'urllib3', 'http', 'idna', 'certifi', 'setuptools', 'astor', 'charset_normalizer']
missingPkgs = ['Microsoft.CognitiveServices.Speech.core.dll', 'decorator.py', 'google', 'paddleocr', 'PIL', 'requests', 'urllib3', 'http', 'idna', 'certifi', 'setuptools', 'astor', 'charset_normalizer']
def add_missing_packages(lst):
pkgs = []
......@@ -20,8 +20,8 @@ a = Analysis(
['start.py'],
pathex=[],
binaries=[],
datas=[('res','res')] + pkgPaths,
hiddenimports=[],
datas=[('vits_chinese','vits_chinese')] + [('res','res'),('./deploy.bat','.'),('./ding_notify.conf','.'),('LAVFilters64','LAVFilters64'),('LAVFilters32','LAVFilters32')] + pkgPaths,
hiddenimports=['filecmp'],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
......@@ -38,7 +38,7 @@ exe = EXE(
a.scripts,
[],
exclude_binaries=True,
name='start',
name='无障碍电影制作系统',
debug=False,
bootloader_ignore_signals=False,
strip=False,
......@@ -49,6 +49,7 @@ exe = EXE(
target_arch=None,
codesign_identity=None,
entitlements_file=None,
icon=['res\\images\\eagle_2.ico'],
)
coll = COLLECT(
exe,
......@@ -58,5 +59,5 @@ coll = COLLECT(
strip=False,
upx=True,
upx_exclude=[],
name='start',
name='无障碍电影制作系统',
)
......@@ -38,6 +38,29 @@ def validate_and_get_filepath(file_info) -> Tuple[str, bool]:
return "", False
return file_info[0][0], True
def get_seconds(time_str: str):
try:
# print(">>>>>>>>>>reverse time")
# print(time_str)
if time_str is None or time_str == "":
return time_str
parts = time_str.split(":")
if len(parts) != 3:
return time_str
hour = int(parts[0])
minutes = int(parts[1])
seconds_parts = parts[2].split(".")
if len(seconds_parts) != 2:
return time_str
seconds = int(seconds_parts[0])
milliseconds = int(seconds_parts[1])
total_seconds = hour * 3600 + minutes * 60 + seconds + milliseconds / 1000
return str(total_seconds)
except Exception as e:
print(e)
return time_str
def trans_to_seconds(timePoint: str) -> float:
"""将用户输入的时间字符串转换为秒数
......@@ -47,13 +70,17 @@ def trans_to_seconds(timePoint: str) -> float:
Returns:
float: 时间字符串对应秒数
"""
time_in_seconds = 0
timePoints = timePoint.split(':')
units = 1
for i in range(len(timePoints) - 1, -1, -1):
time_in_seconds += units * float(timePoints[i])
units *= 60
return time_in_seconds
# time_in_seconds = 0
# timePoints = timePoint.split(':')
# units = 1
# for i in range(len(timePoints) - 1, -1, -1):
# time_in_seconds += units * float(timePoints[i])
# units *= 60
# return time_in_seconds
try:
return float(reverse_time_to_seconds(timePoint))
except Exception as e:
return None
def transfer_second_to_time(sec: str) -> str:
"""将秒数转换为"hh:mm:ss.xxx"格式的时间字符串
......@@ -64,13 +91,75 @@ def transfer_second_to_time(sec: str) -> str:
Returns:
str: "hh:mm:ss.xxx"格式的时间字符串
"""
duration = int(float(sec))
hour = int(duration/3600)
minutes = int((duration % 3600)/60)
seconds = int(duration%60)
msec = round((float(sec) - hour * 3600 - minutes * 60 - seconds) * 1000)
time = "%02d:%02d:%02d.%03d" % (hour, minutes, seconds, msec)
return time
try:
duration = int(float(sec))
hour = int(duration/3600)
minutes = int((duration % 3600)/60)
seconds = int(duration%60)
# msec = round((float(sec) - hour * 3600 - minutes * 60 - seconds) * 1000)
# time = "%02d:%02d:%02d.%03d" % (hour, minutes, seconds, msec)
time = "%02d:%02d:%02d" % (hour, minutes, seconds)
return time
except Exception as e:
print(e)
return sec
def transfer_second_to_all_time(sec: str) -> str:
"""将秒数转换为"hh:mm:ss.xxx"格式的时间字符串
Args:
sec (str): 待转换的描述
Returns:
str: "hh:mm:ss.xxx"格式的时间字符串
"""
try:
duration = int(float(sec))
hour = int(duration/3600)
minutes = int((duration % 3600)/60)
seconds = int(duration%60)
msec = round((float(sec) - hour * 3600 - minutes * 60 - seconds) * 1000)
time = "%02d:%02d:%02d.%03d" % (hour, minutes, seconds, msec)
# time = "%02d:%02d:%02d" % (hour, minutes, seconds)
return time
except Exception as e:
print(e)
return sec
def reverse_time_to_seconds(time_str: str) -> str:
"""将"hh:mm:ss.xxx"格式的时间字符串转换为秒数
Args:
time_str (str): 时间字符串,格式为"hh:mm:ss.xxx"
Returns:
float: 对应的秒数
"""
try:
# print(">>>>>>>>>>reverse time")
# print(time_str)
if time_str is None or time_str == "":
return time_str
parts = time_str.split(":")
if len(parts) != 3:
return time_str
hour = int(parts[0])
minutes = int(parts[1])
seconds_parts = parts[2].split(".")
# if len(seconds_parts) != 2:
# return time_str
seconds = int(seconds_parts[0])
# milliseconds = int(seconds_parts[1])
# total_seconds = hour * 3600 + minutes * 60 + seconds + milliseconds / 1000
total_seconds = hour * 3600 + minutes * 60 + seconds
print(str(total_seconds))
return str(total_seconds)
except Exception as e:
print(">>>>>>>>>>reverse time err" + time_str)
print(e)
return time_str
def replace_path_suffix(path: str, new_suffix: str) -> str:
"""替换文件路径后缀
......@@ -93,7 +182,7 @@ def check_sheet_content(book_path: str) -> bool:
bool: True(用户输入的表符合预期) or False(用户输入的表格式不正确,很可能输入错误)
"""
sheet_heads = get_sheetHead(book_path)
need_heads = ['起始时间', '终止时间', '字幕', '建议', '解说脚本']
need_heads = ['起始时间', '终止时间', '字幕', '建议旁白字数', '解说脚本']
if len(sheet_heads) == 0:
return False
......@@ -150,7 +239,8 @@ def get_progress_with_cmd(cmd: str, state=None):
if result is not None:
elapsed_time = result.groupdict()['time']
# 此处可能会出现进度超过100%,未对数值进行纠正
progress = trans_to_seconds(elapsed_time) / trans_to_seconds(duration)
# progress = trans_to_seconds(elapsed_time) / trans_to_seconds(duration)
progress = float(get_seconds(elapsed_time)) / float(get_seconds(duration))
state[0] = pre + progress * 0.2
print(elapsed_time)
print(progress)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment