Skip to content

Commit

Permalink
fix action timing
Browse files Browse the repository at this point in the history
  • Loading branch information
SheepTester committed May 23, 2024
1 parent 51fb3b8 commit 129e6c6
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 33 deletions.
40 changes: 25 additions & 15 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function App () {
{
id: -2,
type: 'annotation',
annotation: { type: 'set-layout', layout: 'avatar-only' }
annotation: { type: 'set-layout', layout: 'slide-only' }
},
{
id: -3,
Expand Down Expand Up @@ -57,8 +57,31 @@ export function App () {
caption => time >= caption.time
) ?? { content: '' }

const canvas = useRef<HTMLCanvasElement>(null)
const context = useRef<CanvasRenderingContext2D | null>(null)
const [size, setSize] = useState({ width: 0, height: 0 })
useEffect(() => {
context.current = canvas.current?.getContext('2d') ?? null

const observer = new ResizeObserver(([{ contentBoxSize }]) => {
const [{ blockSize, inlineSize }] = contentBoxSize
const newSize = {
width: inlineSize * window.devicePixelRatio,
height: blockSize * window.devicePixelRatio
}
setSize(size =>
size.width === newSize.width && size.height === newSize.height
? size
: newSize
)
})
if (canvas.current?.parentElement) {
observer.observe(canvas.current.parentElement)
}
return () => {
observer.disconnect()
}
}, [])

useEffect(() => {
if (context.current) {
Expand All @@ -79,20 +102,7 @@ export function App () {
className='canvas'
width={size.width}
height={size.height}
ref={canvas => {
context.current = canvas?.getContext('2d') ?? null

if (!canvas?.parentElement) {
return
}
new ResizeObserver(([{ contentBoxSize }]) => {
const [{ blockSize, inlineSize }] = contentBoxSize
setSize({
width: inlineSize * window.devicePixelRatio,
height: blockSize * window.devicePixelRatio
})
}).observe(canvas?.parentElement)
}}
ref={canvas}
></canvas>
<div className='caption'>
<span>{caption.content}</span>
Expand Down
22 changes: 21 additions & 1 deletion src/render/render.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Strategy } from '../video-strategy'
import { Layout, Strategy } from '../video-strategy'

const FONT = `'Brix Sans', 'Source Sans 3', sans-serif`

Expand All @@ -25,5 +25,25 @@ export function render (
HEIGHT - PADDING
)

let layout: Layout = 'avatar-only'
for (const action of strategy.actions) {
if (time < action.time) {
break
}
if (action.type === 'set-layout') {
layout = action.layout
}
}

if (layout === 'slide-only') {
context.fillStyle = 'white'
context.fillRect(
PADDING,
PADDING,
WIDTH - PADDING * 2,
HEIGHT - PADDING * 2 - 40
)
}

context.restore()
}
46 changes: 29 additions & 17 deletions src/video-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,22 @@ export function strategize (parts: PartBase[]): Strategy {
const actions: Action[] = []

let time = 0
let captionStartTime = 0
let caption = ''
for (const part of parts) {
if (part.type === 'text') {
const lines = part.content.split(/\s*\n\s*/)
for (const line of lines) {
let lastIndex = 0
for (const { index } of line.matchAll(/\s+/g)) {
// `index` is the index of the first whitespace character
const appendum = line.slice(lastIndex, index)
for (const appendum of splitBySpaces(line)) {
if (caption.length + appendum.length > MAX_CAPTION_LENGTH) {
const content = caption.trim()
captions.push({ content, time })
time += content.replace(/\s/g, '').length * EST_TIME_PER_CHAR
captions.push({ content, time: captionStartTime })
captionStartTime = time
caption = appendum
} else {
caption += appendum
}
lastIndex = index
}
const rest = line.slice(lastIndex)
if (caption.length + rest.length > MAX_CAPTION_LENGTH) {
const content = caption.trim()
captions.push({ content, time })
time += content.replace(/\s/g, '').length * EST_TIME_PER_CHAR
caption = rest
} else {
caption += rest
time += appendum.replace(/\s/g, '').length * EST_TIME_PER_CHAR
}
}
if (caption) {
Expand All @@ -73,9 +62,32 @@ export function strategize (parts: PartBase[]): Strategy {
}
if (caption.length > 0) {
const content = caption.trim()
captions.push({ content, time })
captions.push({ content, time: captionStartTime })
time += content.replace(/\s/g, '').length * EST_TIME_PER_CHAR
}

return { captions, actions, length: time }
}

/**
* Splits a string by whitespace so that every word in the returned list begins
* with some whitespace, except for the first word.
*
* @example
* > Array.from(splitBySpaces('Hi! Hello world!'))
* ['Hi!', ' Hello', ' world!']
*
* > Array.from(splitBySpaces(' Hi! Hello world! '))
* [' Hi!', ' Hello', ' world!', ' ']
*/
function * splitBySpaces (string: string): Generator<string> {
let lastIndex = 0
for (const { index } of string.matchAll(/\s+/g)) {
if (index === 0) {
continue
}
yield string.slice(lastIndex, index)
lastIndex = index
}
yield string.slice(lastIndex)
}

0 comments on commit 129e6c6

Please sign in to comment.