Compare commits
3 commits
f8cbbd55c7
...
f08520e47f
| Author | SHA1 | Date | |
|---|---|---|---|
| f08520e47f | |||
| 1a9f9ecbc1 | |||
| 3edc89d305 |
6 changed files with 414 additions and 15 deletions
11
generate.py
11
generate.py
|
|
@ -1243,20 +1243,27 @@ def process_reshoot_firstframe(character='P1'):
|
||||||
print('>> skip', item)
|
print('>> skip', item)
|
||||||
continue
|
continue
|
||||||
if item.sort.duration > 30:
|
if item.sort.duration > 30:
|
||||||
reshoot_item_segments(item, character)
|
pass
|
||||||
|
#reshoot_item_segments(item, character)
|
||||||
else:
|
else:
|
||||||
cid = get_character_document(character).get_id()
|
cid = get_character_document(character).get_id()
|
||||||
first_frame = item.documents.filter(
|
first_frame = item.documents.filter(
|
||||||
data__character=cid, data__position=position
|
data__character=cid, data__position=position
|
||||||
).order_by('-created').first()
|
).order_by('-created').first()
|
||||||
if not first_frame:
|
if not first_frame:
|
||||||
first_frame = replace_character(item, character, position)
|
try:
|
||||||
|
first_frame = replace_character(item, character, position)
|
||||||
|
except:
|
||||||
|
item.refresh_from_db()
|
||||||
|
add_tag(item, 'ai-failed')
|
||||||
|
print('>> failed', item)
|
||||||
if first_frame.items.filter(data__type__icontains='ai:').exists():
|
if first_frame.items.filter(data__type__icontains='ai:').exists():
|
||||||
continue
|
continue
|
||||||
print(item, first_frame)
|
print(item, first_frame)
|
||||||
try:
|
try:
|
||||||
reshoot_item(item, first_frame=first_frame)
|
reshoot_item(item, first_frame=first_frame)
|
||||||
except:
|
except:
|
||||||
|
item.refresh_from_db()
|
||||||
add_tag(item, 'ai-failed')
|
add_tag(item, 'ai-failed')
|
||||||
print('>> failed', item)
|
print('>> failed', item)
|
||||||
|
|
||||||
|
|
|
||||||
BIN
player/html/Menlo-Regular.ttf
Normal file
BIN
player/html/Menlo-Regular.ttf
Normal file
Binary file not shown.
1
player/html/ass.global.min.js
vendored
Normal file
1
player/html/ass.global.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
367
player/html/index.html
Normal file
367
player/html/index.html
Normal file
|
|
@ -0,0 +1,367 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<title>30 Box Grid</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Menlo';
|
||||||
|
src: url('Menlo-Regular.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
font-family: Menlo, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Full page container */
|
||||||
|
.page {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
background: rgba(0,0,0, 0.5);
|
||||||
|
position: fixed;
|
||||||
|
z-index: 100;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grid container */
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(10, 70px);
|
||||||
|
grid-template-rows: repeat(3, 70px);
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual boxes */
|
||||||
|
.box {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
color: #ffff;
|
||||||
|
background: rgba(0,0,0, 0.6);
|
||||||
|
border: 2px solid #333;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 18px;
|
||||||
|
transition: background 0.2s ease, transform 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box:hover {
|
||||||
|
background: #e0e0e0;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Title display */
|
||||||
|
.title {
|
||||||
|
min-height: 24px;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
color: #ffff;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
background: black;
|
||||||
|
}
|
||||||
|
video {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
#stage {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
video.next {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#subtitles {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: 'Menlo';
|
||||||
|
src: url('Menlo-Regular.ttf') format('truetype');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script src="ass.global.min.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
const sub_handlers = {};
|
||||||
|
var playlist = [
|
||||||
|
"/01_Life/front.mp4",
|
||||||
|
"/02_Seeing/front.mp4",
|
||||||
|
"/03_Capacity/front.mp4",
|
||||||
|
"/04_Landscape/front.mp4",
|
||||||
|
"/05_Relations/front.mp4",
|
||||||
|
"/06_Will/front.mp4",
|
||||||
|
"/07_Self/front.mp4",
|
||||||
|
"/08_Field/front.mp4",
|
||||||
|
"/09_Theatre/front.mp4",
|
||||||
|
"/10_Substance/front.mp4",
|
||||||
|
"/11_Science/front.mp4",
|
||||||
|
"/12_Energy/front.mp4",
|
||||||
|
"/13_Geopolitics/front.mp4",
|
||||||
|
"/14__Chance/front.mp4",
|
||||||
|
"/15_Morality/front.mp4",
|
||||||
|
"/16_Evolution/front.mp4",
|
||||||
|
"/17_Computing/front.mp4",
|
||||||
|
"/18_Semi-Conductors/front.mp4",
|
||||||
|
"/19_Love/front.mp4",
|
||||||
|
"/20_Reversibility/front.mp4",
|
||||||
|
"/21_Weakness/front.mp4",
|
||||||
|
"/22_Elections/front.mp4",
|
||||||
|
"/23_People/front.mp4",
|
||||||
|
"/24_Corporation/front.mp4",
|
||||||
|
"/25_Instruments/front.mp4",
|
||||||
|
"/26_Practice/front.mp4",
|
||||||
|
"/27_Weaponry/front.mp4",
|
||||||
|
"/28_Art/front.mp4",
|
||||||
|
"/29_Help/front.mp4",
|
||||||
|
"/30_Self-help/front.mp4",
|
||||||
|
]
|
||||||
|
//var prefix = '../render/'
|
||||||
|
var prefix = 'https://power.0x2620.org/static/render/'
|
||||||
|
var current = 0, name
|
||||||
|
var currentVideo, nextVideo;
|
||||||
|
function ended(event) {
|
||||||
|
const next = nextVideo;
|
||||||
|
currentVideo.classList.add('next')
|
||||||
|
sub_handlers[currentVideo.id]?.destroy()
|
||||||
|
nextVideo.classList.remove('next')
|
||||||
|
console.log("play next", nextVideo)
|
||||||
|
nextVideo.play()
|
||||||
|
sub_handlers[nextVideo.id]?.show()
|
||||||
|
current +=1
|
||||||
|
if (current >= playlist.length) {
|
||||||
|
current = 0
|
||||||
|
}
|
||||||
|
currentVideo.src = prefix + name + playlist[current]
|
||||||
|
nextVideo = currentVideo
|
||||||
|
currentVideo = next
|
||||||
|
sub_handlers[nextVideo.id]?.destroy()
|
||||||
|
fetch(nextVideo.src.replace(/.mp4/, '.ass')).then(async (res) => {
|
||||||
|
const content = await res.text()
|
||||||
|
const ass = new ASS(content, nextVideo, {
|
||||||
|
container: subtitles,
|
||||||
|
});
|
||||||
|
sub_handlers[nextVideo.id] = ass
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const titles = [
|
||||||
|
"Life",
|
||||||
|
"Seeing",
|
||||||
|
"Capacity",
|
||||||
|
"Landscape",
|
||||||
|
"Relations",
|
||||||
|
"Will",
|
||||||
|
"Self",
|
||||||
|
"Field",
|
||||||
|
"Theatre",
|
||||||
|
"Substance",
|
||||||
|
"Science",
|
||||||
|
"Energy",
|
||||||
|
"Geopolitics",
|
||||||
|
"Chance",
|
||||||
|
"Morality",
|
||||||
|
"Evolution",
|
||||||
|
"Computing",
|
||||||
|
"Semi-Conductors",
|
||||||
|
"Love",
|
||||||
|
"Reversibility",
|
||||||
|
"Weakness",
|
||||||
|
"Elections",
|
||||||
|
"People",
|
||||||
|
"Corporation",
|
||||||
|
"Instruments",
|
||||||
|
"Practice",
|
||||||
|
"Weaponry",
|
||||||
|
"Art",
|
||||||
|
"Help",
|
||||||
|
"Self-help",
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
name = document.location.hash.slice(1)
|
||||||
|
const parts = name.split('/')
|
||||||
|
if (parts.length == 2) {
|
||||||
|
name = parts[0]
|
||||||
|
current = parseInt(parts[1]) - 1
|
||||||
|
}
|
||||||
|
var body = document.querySelector('body')
|
||||||
|
body.innerHTML = ``
|
||||||
|
var stage = document.createElement("div")
|
||||||
|
stage.id = "stage"
|
||||||
|
body.appendChild(stage)
|
||||||
|
|
||||||
|
var overlay = document.createElement("div")
|
||||||
|
overlay.id = "overlay"
|
||||||
|
body.appendChild(overlay)
|
||||||
|
overlay.innerHTML = `
|
||||||
|
<div class="page">
|
||||||
|
<div class="grid" id="grid"></div>
|
||||||
|
<div class="title" id="title"></div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
const grid = overlay.querySelector("#grid");
|
||||||
|
const titleEl = overlay.querySelector("#title");
|
||||||
|
for (let i = 1; i <= 30; i++) {
|
||||||
|
const box = document.createElement("div");
|
||||||
|
box.className = "box";
|
||||||
|
box.textContent = i;
|
||||||
|
|
||||||
|
box.addEventListener("mouseenter", () => {
|
||||||
|
titleEl.textContent = titles[i - 1];
|
||||||
|
});
|
||||||
|
|
||||||
|
box.addEventListener("mouseleave", () => {
|
||||||
|
titleEl.textContent = "";
|
||||||
|
});
|
||||||
|
box.addEventListener("click", () => {
|
||||||
|
console.log("clicked", box.textContent)
|
||||||
|
document.querySelector(".page").style.display = ""
|
||||||
|
current = parseInt(box.textContent) - 1
|
||||||
|
nextVideo.src = prefix + name + playlist[current]
|
||||||
|
fetch(nextVideo.src.replace(/.mp4/, '.ass')).then(async (res) => {
|
||||||
|
const content = await res.text()
|
||||||
|
const ass = new ASS(content, nextVideo, {
|
||||||
|
container: subtitles,
|
||||||
|
});
|
||||||
|
sub_handlers[nextVideo.id] = ass
|
||||||
|
ended()
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
grid.appendChild(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
var subtitles = document.createElement("div")
|
||||||
|
subtitles.id = "subtitles"
|
||||||
|
stage.appendChild(subtitles)
|
||||||
|
|
||||||
|
var video1 = document.createElement("video")
|
||||||
|
video1.src = prefix + name + playlist[current]
|
||||||
|
video1.id = 'v1'
|
||||||
|
video1.controls = false
|
||||||
|
video1.preload = "auto"
|
||||||
|
video1.addEventListener('ended', ended)
|
||||||
|
stage.appendChild(video1)
|
||||||
|
currentVideo = video1
|
||||||
|
|
||||||
|
current +=1
|
||||||
|
var video2 = document.createElement("video")
|
||||||
|
video2.src = prefix + name + playlist[current]
|
||||||
|
video1.id = 'v2'
|
||||||
|
video2.classList.add("next")
|
||||||
|
video2.controls = false
|
||||||
|
video2.preload = "auto"
|
||||||
|
video2.addEventListener('ended', ended)
|
||||||
|
stage.appendChild(video2)
|
||||||
|
nextVideo = video2
|
||||||
|
|
||||||
|
var audio2 = document.createElement("audio")
|
||||||
|
audio2.src = prefix + 'forest-5.1.mp4'
|
||||||
|
audio2.controls = false
|
||||||
|
audio2.volume = 1
|
||||||
|
audio2.loop = true
|
||||||
|
audio2.autoplay = true
|
||||||
|
audio2.classList.add("forest")
|
||||||
|
body.appendChild(audio2)
|
||||||
|
|
||||||
|
var audio3 = document.createElement("audio")
|
||||||
|
audio3.src = prefix + 'music-5.1.mp4'
|
||||||
|
audio3.controls = false
|
||||||
|
audio3.volume = 1
|
||||||
|
audio3.loop = true
|
||||||
|
audio3.autoplay = true
|
||||||
|
audio3.currentTime = Math.random() * 60
|
||||||
|
audio3.classList.add("music")
|
||||||
|
body.appendChild(audio3)
|
||||||
|
|
||||||
|
document.querySelectorAll('video,audio').forEach(media => {
|
||||||
|
media.addEventListener('play', sync)
|
||||||
|
media.addEventListener('pause', sync)
|
||||||
|
media.addEventListener('click', () => {
|
||||||
|
document.querySelector(".page").style.display = "flex"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
fetch(video1.src.replace(/.mp4/, '.ass')).then(async (res) => {
|
||||||
|
const content = await res.text()
|
||||||
|
const ass = new ASS(content, video1, {
|
||||||
|
container: subtitles,
|
||||||
|
});
|
||||||
|
sub_handlers[video1.id] = ass
|
||||||
|
sub_handlers[video1.id].show()
|
||||||
|
})
|
||||||
|
video1.play()
|
||||||
|
fetch(video2.src.replace(/.mp4/, '.ass')).then(async (res) => {
|
||||||
|
const content = await res.text()
|
||||||
|
const ass = new ASS(content, video2, {
|
||||||
|
container: subtitles,
|
||||||
|
});
|
||||||
|
sub_handlers[video2.id] = ass
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function sync(event) {
|
||||||
|
var src = event.target
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
return
|
||||||
|
document.querySelectorAll('video,audio').forEach(media => {
|
||||||
|
if (media.classList.contains('next')) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (media != src) {
|
||||||
|
if (!src.paused) {
|
||||||
|
console.log("play", media.id)
|
||||||
|
media.play()
|
||||||
|
} else {
|
||||||
|
console.log("pause", media.id, src.paused)
|
||||||
|
media.pause()
|
||||||
|
}
|
||||||
|
media.paused = src.paused
|
||||||
|
if (media.classList.contains('music') || media.classList.contains('forest')) {
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
//media.currentTime = src.currentTime
|
||||||
|
console.log(media.currentTime, src.currentTime)
|
||||||
|
}
|
||||||
|
console.log(media, media.paused, src.paused)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
window.addEventListener("hashchange", event=>{
|
||||||
|
render()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!document.location.hash.slice(1).length) {
|
||||||
|
document.location.hash = '#0'
|
||||||
|
}
|
||||||
|
render()
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
49
render.py
49
render.py
|
|
@ -248,6 +248,7 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
vo = voice_over[vo_key][variant]
|
vo = voice_over[vo_key][variant]
|
||||||
if isinstance(vo, list):
|
if isinstance(vo, list):
|
||||||
vo, vo_b = vo
|
vo, vo_b = vo
|
||||||
|
|
||||||
else:
|
else:
|
||||||
vo_b = None
|
vo_b = None
|
||||||
while int((vo['duration'] + sub_offset) * fps) > scene_duration:
|
while int((vo['duration'] + sub_offset) * fps) > scene_duration:
|
||||||
|
|
@ -285,7 +286,7 @@ def compose(clips, fragment, target=150, base=1024, voice_over=None, options=Non
|
||||||
scene['audio-center']['A2'].append(vo_b)
|
scene['audio-center']['A2'].append(vo_b)
|
||||||
vo_b = vo_b.copy()
|
vo_b = vo_b.copy()
|
||||||
vo_b['filter'] = {'volume': b}
|
vo_b['filter'] = {'volume': b}
|
||||||
scene['audio-rear']['A1'].append(vo_b)
|
scene['audio-rear']['A2'].append(vo_b)
|
||||||
else:
|
else:
|
||||||
for tl, track in (
|
for tl, track in (
|
||||||
('audio-center', 'A2'),
|
('audio-center', 'A2'),
|
||||||
|
|
@ -621,18 +622,24 @@ def render_all(options):
|
||||||
if abs(duration_a - duration_b) > 1/48:
|
if abs(duration_a - duration_b) > 1/48:
|
||||||
print('!!', duration_a, fragment_prefix / a)
|
print('!!', duration_a, fragment_prefix / a)
|
||||||
print('!!', duration_b, fragment_prefix / b)
|
print('!!', duration_b, fragment_prefix / b)
|
||||||
sys.exit(-1)
|
#sys.exit(-1)
|
||||||
shutil.move(fragment_prefix / "front-mixed.mp4", fragment_prefix / "front.mp4")
|
shutil.move(fragment_prefix / "front-mixed.mp4", fragment_prefix / "front.mp4")
|
||||||
if options["keep_audio"]:
|
cleanup = [
|
||||||
shutil.move(fragment_prefix / "audio-center.wav", fragment_prefix / "vocals.wav")
|
|
||||||
shutil.move(fragment_prefix / "audio-front.wav", fragment_prefix / "foley.wav")
|
|
||||||
for fn in (
|
|
||||||
"audio-5.1.mp4",
|
"audio-5.1.mp4",
|
||||||
"audio-center.wav", "audio-rear.wav",
|
"audio-center.wav", "audio-rear.wav",
|
||||||
"audio-front.wav",
|
"audio-front.wav",
|
||||||
"fl.wav", "fr.wav", "fc.wav", "lfe.wav", "bl.wav", "br.wav",
|
"fl.wav", "fr.wav", "fc.wav", "lfe.wav", "bl.wav", "br.wav",
|
||||||
"audio-stereo.wav",
|
"audio-stereo.wav",
|
||||||
):
|
]
|
||||||
|
if options["keep_audio"]:
|
||||||
|
shutil.move(fragment_prefix / "audio-center.wav", fragment_prefix / "vocals.wav")
|
||||||
|
shutil.move(fragment_prefix / "audio-front.wav", fragment_prefix / "foley.wav")
|
||||||
|
else:
|
||||||
|
cleanup += [
|
||||||
|
"vocals.wav",
|
||||||
|
"foley.wav"
|
||||||
|
]
|
||||||
|
for fn in cleanup:
|
||||||
fn = fragment_prefix / fn
|
fn = fragment_prefix / fn
|
||||||
if os.path.exists(fn):
|
if os.path.exists(fn):
|
||||||
os.unlink(fn)
|
os.unlink(fn)
|
||||||
|
|
@ -959,9 +966,6 @@ def generate_clips(options):
|
||||||
if not durations:
|
if not durations:
|
||||||
print(i.public_id, 'no duration!', clip)
|
print(i.public_id, 'no duration!', clip)
|
||||||
continue
|
continue
|
||||||
if len(set(durations)) > 1:
|
|
||||||
print(clip, durations)
|
|
||||||
|
|
||||||
clip["duration"] = min(durations) - 1/24
|
clip["duration"] = min(durations) - 1/24
|
||||||
# trim to a multiple of the output fps
|
# trim to a multiple of the output fps
|
||||||
d1 = format_duration(clip["duration"], fps)
|
d1 = format_duration(clip["duration"], fps)
|
||||||
|
|
@ -1009,7 +1013,7 @@ def generate_clips(options):
|
||||||
|
|
||||||
fragment = '%02d' % int(parts[0].replace('ch', ''))
|
fragment = '%02d' % int(parts[0].replace('ch', ''))
|
||||||
type = parts[1]
|
type = parts[1]
|
||||||
variant = '-'.join(parts[2:4])
|
variant = '-'.join(parts[2:]).split('-ElevenLabs')[0]
|
||||||
source = vo.files.filter(selected=True)[0]
|
source = vo.files.filter(selected=True)[0]
|
||||||
src = source.data.path
|
src = source.data.path
|
||||||
ext = src.split('.')[-1]
|
ext = src.split('.')[-1]
|
||||||
|
|
@ -1028,12 +1032,31 @@ def generate_clips(options):
|
||||||
voice_over[fragment] = {}
|
voice_over[fragment] = {}
|
||||||
if type not in voice_over[fragment]:
|
if type not in voice_over[fragment]:
|
||||||
voice_over[fragment][type] = []
|
voice_over[fragment][type] = []
|
||||||
voice_over[fragment][type].append({
|
vo_variant = {
|
||||||
"variant": variant,
|
"variant": variant,
|
||||||
"src": target,
|
"src": target,
|
||||||
#"duration": format_duration(source.duration, fps, True),
|
#"duration": format_duration(source.duration, fps, True),
|
||||||
"duration": source.duration,
|
"duration": source.duration,
|
||||||
"subs": subs
|
"subs": subs
|
||||||
})
|
}
|
||||||
|
done = False
|
||||||
|
if type == 'quote':
|
||||||
|
if '-a-t' in variant:
|
||||||
|
b_variant = variant.replace('-a-t', '-b-t').split('-t')[0]
|
||||||
|
for old in voice_over[fragment][type]:
|
||||||
|
print(type(old))
|
||||||
|
if isinstance(old, list) and old[0]['variant'].startswith(b_variant):
|
||||||
|
old.insert(0, vo_variant)
|
||||||
|
done = True
|
||||||
|
elif '-b-t' in variant:
|
||||||
|
a_variant = variant.replace('-b-t', '-a-t').split('-t')[0]
|
||||||
|
for old in voice_over[fragment][type]:
|
||||||
|
if isinstance(old, list) and old[0]['variant'].startswith(a_variant):
|
||||||
|
old.append(vo_variant)
|
||||||
|
done = True
|
||||||
|
if not done and '-a-t' in variant or '-b-t' in variant:
|
||||||
|
vo_variant = [vo_variant]
|
||||||
|
if not done:
|
||||||
|
voice_over[fragment][type].append(vo_variant)
|
||||||
with open(os.path.join(prefix, 'voice_over.json'), 'w') as fd:
|
with open(os.path.join(prefix, 'voice_over.json'), 'w') as fd:
|
||||||
json.dump(voice_over, fd, indent=2, ensure_ascii=False)
|
json.dump(voice_over, fd, indent=2, ensure_ascii=False)
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,7 @@ Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour,
|
||||||
stop = ass_timestamp(sub["out"])
|
stop = ass_timestamp(sub["out"])
|
||||||
for lang in reversed(langs):
|
for lang in reversed(langs):
|
||||||
value = sub["values"][lang]
|
value = sub["values"][lang]
|
||||||
|
value = value.replace('\n', '\\N')
|
||||||
event = f"Dialogue: 0,{start},{stop},{lang},,0,0,0,,{value}"
|
event = f"Dialogue: 0,{start},{stop},{lang},,0,0,0,,{value}"
|
||||||
events.append(event)
|
events.append(event)
|
||||||
ass += "\n\n[Events]\n" + "\n".join(events) + "\n"
|
ass += "\n\n[Events]\n" + "\n".join(events) + "\n"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue