Files
epub-tts/src/epub_tts/postprocess.py
T
2026-08-10 16:37:59 -03:00

112 lines
3.0 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (c) 2025-2026 Renato Xavier da Silveira Rosa
# See [LICENSE](./LICENSE) or [BSD-3-Clause-Clear](https://spdx.org/licenses/BSD-3-Clause-Clear.html)
"""Postprocess audio files into an audiobook.
"""
import subprocess
# stdlib modules
import os
import sys
# pip installed packages
import numpy as np
import soundfile
import torch
from tqdm import tqdm
from kokoro import KPipeline
from ebooklib import epub
import soundfile as sf
from mutagen import mp4
from pydub import AudioSegment
from mutagen import mp4
# Local imports
from .tts_generic import GenericTTSBackend
from . import logger, PathLike
from .preprocess import preprocess_book
def generate_metadata(files, author, title, chapter_titles):
chap = 0
start_time = 0
with open("FFMETADATAFILE", "w") as file:
file.write(";FFMETADATA1\n")
file.write(f"ARTIST={author}\n")
file.write(f"ALBUM={title}\n")
file.write(f"TITLE={title}\n")
file.write("DESCRIPTION=Made with https://github.com/aedocw/epub2tts-kokoro\n")
for file_name in files:
duration = get_duration(file_name)
file.write("[CHAPTER]\n")
file.write("TIMEBASE=1/1000\n")
file.write(f"START={start_time}\n")
file.write(f"END={start_time + duration}\n")
file.write(f"title={chapter_titles[chap]}\n")
chap += 1
start_time += duration
def get_duration(file_path):
audio = AudioSegment.from_file(file_path)
duration_milliseconds = len(audio)
return duration_milliseconds
def make_m4b(files, sourcefile, speaker):
filelist = "filelist.txt"
basefile = sourcefile.replace(".txt", "")
outputm4a = f"{basefile} ({speaker}).m4a"
outputm4b = f"{basefile} ({speaker}).m4b"
with open(filelist, "w") as f:
for filename in files:
filename = filename.replace("'", "'\\''")
f.write(f"file '{filename}'\n")
ffmpeg_command = [
"ffmpeg",
"-f",
"concat",
"-safe",
"0",
"-i",
filelist,
"-codec:a",
"flac",
"-f",
"mp4",
"-strict",
"-2",
outputm4a,
]
subprocess.run(ffmpeg_command)
ffmpeg_command = [
"ffmpeg",
"-i",
outputm4a,
"-i",
"FFMETADATAFILE",
"-map_metadata",
"1",
"-codec",
"aac",
outputm4b,
]
subprocess.run(ffmpeg_command)
os.remove(filelist)
os.remove("FFMETADATAFILE")
os.remove(outputm4a)
for f in files:
os.remove(f)
return outputm4b
def add_cover(cover_img, filename):
try:
if os.path.isfile(cover_img):
m4b = mp4.MP4(filename)
cover_image = open(cover_img, "rb").read()
m4b["covr"] = [mp4.MP4Cover(cover_image)]
m4b.save()
else:
print(f"Cover image {cover_img} not found")
except:
print(f"Cover image {cover_img} not found")