简介:
使用edge-tts朗读txt文本。拥有“断点续读”的功能。会缓存一大堆的mp3文件,可以手动清理,也可以动手合成一个音频发b站之类的。: )
20231205更新:
现在把源码上传到gitee了,方便手机用termux时克隆代码到本地。txtReader: termux 上使用 或 windows 上使用的 txt阅读器 (gitee.com)
git clone https://gitee.com/harryxiaocn/txt-reader.git
20230921更新:
为了避免缓存不够,听起来断断续续的,现在三线程同时下载音频……
源码(已过期,以仓库内源码为准):
# coding=utf-8
import json
import os.path
import threading
import time
import edge_tts as et
from playsound import playsound
import asyncio
"""
准备工作:
1、pip3 install edge_tts
2、pip3 install playsound
"""
def RTxt(path):
with open(path, encoding='utf8') as f:
return f.read()
def WTxt(path, content):
with open(path, 'w', encoding='utf8') as f:
f.write(content)
class Reader:
def __init__(self, txtPath):
self.novel = RTxt(txtPath)
self.novelName = os.path.basename(txtPath).split('.')[0]
self.lines = self.novel.split('\n')
self.setting = {'pos': 0, 'downloadPos': 0}
self.sayProcess = None
if os.path.exists('setting.json'):
self.setting = json.loads(RTxt('setting.json'))
self.end = False
def Start(self):
def Download():
while self.setting['downloadPos'] < len(self.lines):
line = self.lines[self.setting['downloadPos']]
try:
self.Download(line)
except Exception as e:
print('Download.e=', e, self.setting['downloadPos'])
WTxt('setting.json', json.dumps(self.setting))
while self.setting['downloadPos'] > self.setting['pos'] + 300:
time.sleep(1)
def Say():
while self.setting['pos'] < len(self.lines):
while self.setting['downloadPos'] < self.setting['pos'] + 10:
print('等待缓存中……')
time.sleep(1)
# print('下载行=', self.setting['downloadPos'])
# print('朗读行=', self.setting['pos'])
print('朗读行=', self.lines[self.setting['pos']], self.setting['pos'], self.setting['downloadPos'])
self.Say()
self.setting['pos'] += 1
downloadThread = threading.Thread(target=Download, daemon=True)
downloadThread.start()
downloadThread2 = threading.Thread(target=Download, daemon=True)
downloadThread2.start()
downloadThread3 = threading.Thread(target=Download, daemon=True)
downloadThread3.start()
sayThread = threading.Thread(target=Say, daemon=True)
sayThread.start()
sayThread.join()
def Download(self, text, voice='zh-CN-YunxiNeural', rate='+25%', volume='+0%'):
mp3Path = 'temp\\{}_{}.mp3'.format(self.novelName, self.setting['downloadPos'])
try:
self.setting['downloadPos'] += 1
async def Do():
await t.save(mp3Path)
t = et.Communicate(text=text, voice=voice, rate=rate, volume=volume)
asyncio.run(Do())
except Exception as e:
print('[error]Download.e=', e, mp3Path)
def Say(self):
"""朗读"""
mp3Path = 'temp\\{}_{}.mp3'.format(self.novelName, self.setting['pos'])
if os.path.exists(mp3Path) and os.path.getsize(mp3Path) > 0:
try:
playsound('{}\\{}'.format(os.getcwd(), mp3Path))
except Exception as e:
print('[error]Say.e=', e)
if __name__ == '__main__':
reader = Reader('小说.txt')
reader.Start()
print('程序终止!')
暂停之类的功能实现起来比较麻烦,就没弄了。