player
parent
41388b8f3f
commit
f5fbe5d42e
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
import re, sys, re, json, math
|
||||
|
||||
"""
|
||||
Usage:
|
||||
|
||||
ogginfo some.ogg | python3 ogginfo-to-srt.py > some.json
|
||||
|
||||
|
||||
EXAMPLE OF OGGINFO OUTPUT
|
||||
|
||||
User comments section follows...
|
||||
title=one
|
||||
ENCODER=Liquidsoap/1.3.3 (Unix; OCaml 4.05.0)
|
||||
Vorbis stream 1:
|
||||
Total data length: 2882 bytes
|
||||
Playback length: 0m:00.704s
|
||||
Average bitrate: 32.731445 kb/s
|
||||
"""
|
||||
|
||||
|
||||
################################
|
||||
# PASS 1: Read the structure
|
||||
|
||||
def parse_ogginfo_output(f):
|
||||
state = ""
|
||||
output = {}
|
||||
output['streams'] = streams = []
|
||||
time = 0.0
|
||||
|
||||
for line in f:
|
||||
# for debugging
|
||||
# print (line.rstrip())
|
||||
|
||||
if line.startswith("User comments section follows..."):
|
||||
print ("COMMENTS", file=sys.stderr)
|
||||
state = "comments"
|
||||
stream = {}
|
||||
stream['comments'] = comments = {}
|
||||
streams.append(stream)
|
||||
elif line.startswith("Vorbis stream"):
|
||||
print ("STREAM", file=sys.stderr)
|
||||
state = "stream"
|
||||
if 'stream' in stream:
|
||||
stream = {}
|
||||
stream['stream'] = streaminfo = {}
|
||||
streams.append(stream)
|
||||
else:
|
||||
stream['stream'] = streaminfo = {}
|
||||
|
||||
elif line.startswith("Logical stream"):
|
||||
print ("EXIT STATE", file=sys.stderr)
|
||||
state = ""
|
||||
else:
|
||||
if state == "comments":
|
||||
name, value = line.strip().split("=", 1)
|
||||
name = name.strip()
|
||||
value = value.strip()
|
||||
print ("comment", (name, value), file=sys.stderr)
|
||||
comments[name] = value
|
||||
elif state == "stream":
|
||||
name, value = line.strip().split(":", 1)
|
||||
name = name.strip()
|
||||
value = value.strip()
|
||||
print ("stream", (name, value), file=sys.stderr)
|
||||
streaminfo[name] = value
|
||||
|
||||
return output
|
||||
|
||||
################################
|
||||
# PASS 2: Add start time, duration, and timecodes
|
||||
|
||||
def parse_ogginfo_time (t):
|
||||
m = re.search(r"(\d+)m\:(\d+\.\d+)s", t)
|
||||
if m:
|
||||
m, s = m.groups()
|
||||
m = int(m)
|
||||
s = float(s)
|
||||
return (m*60)+s
|
||||
|
||||
def timecode_fromsecs(rawsecs, fract=True, alwaysfract=True, fractdelim='.', alwayshours=False):
|
||||
# returns a string in HH:MM:SS[.xxx] notation
|
||||
# if fract is True, uses .xxx if either necessary (non-zero)
|
||||
# OR alwaysfract is True
|
||||
hours = math.floor(rawsecs / 3600)
|
||||
rawsecs -= hours * 3600
|
||||
mins = math.floor(rawsecs / 60)
|
||||
rawsecs -= mins * 60
|
||||
if fract:
|
||||
secs = math.floor(rawsecs)
|
||||
rawsecs -= secs
|
||||
if (rawsecs > 0 or alwaysfract):
|
||||
fract = "%.03f" % rawsecs
|
||||
if hours or alwayshours:
|
||||
return "%02d:%02d:%02d%s%s" % (hours, mins, secs, fractdelim, \
|
||||
fract[2:])
|
||||
else:
|
||||
return "%02d:%02d%s%s" % (mins, secs, fractdelim, fract[2:])
|
||||
else:
|
||||
if hours or alwayshours:
|
||||
return "%02d:%02d:%02d" % (hours, mins, secs)
|
||||
else:
|
||||
return "%02d:%02d" % (mins, secs)
|
||||
|
||||
def add_timing (output):
|
||||
t = 0.0
|
||||
for d in output['streams']:
|
||||
duration_seconds = parse_ogginfo_time(d['stream']['Playback length'])
|
||||
d['start_time'] = t
|
||||
d['start_time_timecode'] = timecode_fromsecs(t)
|
||||
d['duration'] = duration_seconds
|
||||
d['duration_timecode'] = timecode_fromsecs(duration_seconds)
|
||||
t += duration_seconds
|
||||
|
||||
def nextiter (items):
|
||||
prev_item = None
|
||||
for x in items:
|
||||
if (prev_item):
|
||||
yield prev_item, x
|
||||
prev_item = x
|
||||
yield x, None
|
||||
|
||||
def print_srt(data, last_subtitle_duration=5.0, file=None):
|
||||
for cur, nxt in nextiter(data['streams']):
|
||||
if nxt:
|
||||
print ("{} --> {}".format(cur['start_time_timecode'], nxt['start_time_timecode']), file=file)
|
||||
print (json.dumps(cur['comments']), file=file)
|
||||
print (file=file)
|
||||
else:
|
||||
end_timecode = timecode_fromsecs(cur['start_time'] + last_subtitle_duration)
|
||||
print ("{} --> {}".format(cur['start_time_timecode'], end_timecode), file=file)
|
||||
print (json.dumps(cur['comments']), file=file)
|
||||
print (file=file)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
|
||||
ap = argparse.ArgumentParser("")
|
||||
ap.add_argument("--input", type=argparse.FileType("r"), default=sys.stdin)
|
||||
ap.add_argument("--output", type=argparse.FileType("w"), default=sys.stdout)
|
||||
ap.add_argument("--last-subtitle-duration", type=float, default=5.0)
|
||||
ap.add_argument("--json", default=False, action="store_true")
|
||||
ap.add_argument("--vtt", default=False, action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
output = parse_ogginfo_output(args.input)
|
||||
add_timing(output)
|
||||
if args.json:
|
||||
print (json.dumps(output, indent=2), file=args.output)
|
||||
else:
|
||||
if args.vtt:
|
||||
print ("""WEBVTT
|
||||
Kind: captions
|
||||
Language: en
|
||||
""", file=args.output)
|
||||
print_srt(output, last_subtitle_duration=args.last_subtitle_duration, file=args.output)
|
||||
|
@ -0,0 +1,11 @@
|
||||
lineno=0
|
||||
while read line
|
||||
do
|
||||
lineno=$((lineno+1))
|
||||
espeak "$line"
|
||||
filename=`printf "speech%04d" $lineno`
|
||||
espeak "$line" -w "$filename.wav"
|
||||
ffmpeg -i "$filename.wav" -metadata title="$line" -y $filename.mp3 > /dev/null 2> /dev/null
|
||||
# rm "$filename.wav"
|
||||
done
|
||||
|
Loading…
Reference in New Issue