Skip to content

Instantly share code, notes, and snippets.

@Ainali
Created April 17, 2022 13:38
Show Gist options
  • Save Ainali/74d540788a8f188677690ddc78ba1f9c to your computer and use it in GitHub Desktop.
Save Ainali/74d540788a8f188677690ddc78ba1f9c to your computer and use it in GitHub Desktop.
Add chapters to mp3 file based on Audacity label export (modified from https://github.com/trevligmjukvara/production-scripts/blob/master/produce-chapters.py )
#!/usr/bin/env python
# *-* encoding: utf-8 -*-
"""
Usage:
produce-chapters.py <part1_flac> <audacity_labels_part1> <target_mp3>
"""
from eyed3.id3 import Tag
from eyed3 import core
import os
import sys
from docopt import docopt
from tinytag import TinyTag # for flac length parsing
from pydub import AudioSegment
from pathlib import Path
import subprocess
import tempfile
class Chapter:
start = 0
end = 0
title = "title"
def parse_chapters_file(fname, offset_ms):
chaps = []
with open(fname, "r") as f:
for line in f.readlines():
time, title = line.split()[0], u" ".join(line.split()[2:])
timeMs = int((float(time)*1000) + offset_ms)
chap = Chapter()
chap.start = timeMs
chap.title = title
chaps.append(chap)
print("{} seconds in: '{}'".format(timeMs/1000, title))
return chaps
def add_chapters(fname, chaps):
tag = Tag()
tag.parse(fname)
audioFile = core.load(fname)
total_length = audioFile.info.time_secs * 1000
tag.setTextFrame(b"TLEN", str(int(total_length)))
for i, chap in enumerate(chaps):
if i < (len(chaps)-1):
chap.end = chaps[i+1].start
chaps[-1].end = total_length
index = 0
child_ids = []
for chap in chaps:
element_id = "ch{}".format(index).encode()
print("Adding chapter {} at {}".format(chap.title, chap.start))
new_chap = tag.chapters.set(element_id, (chap.start, chap.end))
new_chap.sub_frames.setTextFrame(b"TIT2", u"{}".format(chap.title))
child_ids.append(element_id)
index += 1
tag.table_of_contents.set(b"toc", child_ids=child_ids)
list_chaps(tag)
tag.save()
def list_chaps(tag):
"list chapters in tag"
print("Chapters:")
for chap in tag.chapters:
print(chap.sub_frames.get(b"TIT2")[0]._text)
def main():
"Entry point"
print("Part1 {}, target {}".format(sys.argv[1], sys.argv[2]))
part1_length = TinyTag.get(sys.argv[1]).duration * 1000
print("P1 length: {} s".format(part1_length / 1000))
chapters_p1_file = sys.argv[2]
target_mp3 = sys.argv[3]
title = sys.argv[4]
chapters = []
chapters += parse_chapters_file(chapters_p1_file, 0)
print(len(chapters))
add_chapters(target_mp3, chapters)
print("MP3 PRODUCED")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment