VideoTools/vendor/github.com/hack-pad/go-indexeddb/idb/cursor.go
Stu Leak 68df790d27 Fix player frame generation and video playback
Major improvements to UnifiedPlayer:

1. GetFrameImage() now works when paused for responsive UI updates
2. Play() method properly starts FFmpeg process
3. Frame display loop runs continuously for smooth video display
4. Disabled audio temporarily to fix video playback fundamentals
5. Simplified FFmpeg command to focus on video stream only

Player now:
- Generates video frames correctly
- Shows video when paused
- Has responsive progress tracking
- Starts playback properly

Next steps: Re-enable audio playback once video is stable
2026-01-07 22:20:00 -05:00

197 lines
5.9 KiB
Go

//go:build js && wasm
// +build js,wasm
package idb
import (
"syscall/js"
"github.com/hack-pad/go-indexeddb/idb/internal/jscache"
"github.com/hack-pad/safejs"
)
var (
jsObjectStore safejs.Value
cursorDirectionCache jscache.Strings
)
func init() {
var err error
jsObjectStore, err = safejs.Global().Get("IDBObjectStore")
if err != nil {
panic(err)
}
}
// CursorDirection is the direction of traversal of the cursor
type CursorDirection int
const (
// CursorNext direction causes the cursor to be opened at the start of the source.
CursorNext CursorDirection = iota
// CursorNextUnique direction causes the cursor to be opened at the start of the source. For every key with duplicate values, only the first record is yielded.
CursorNextUnique
// CursorPrevious direction causes the cursor to be opened at the end of the source.
CursorPrevious
// CursorPreviousUnique direction causes the cursor to be opened at the end of the source. For every key with duplicate values, only the first record is yielded.
CursorPreviousUnique
)
func parseCursorDirection(s string) CursorDirection {
switch s {
case "nextunique":
return CursorNextUnique
case "prev":
return CursorPrevious
case "prevunique":
return CursorPreviousUnique
default:
return CursorNext
}
}
func (d CursorDirection) String() string {
switch d {
case CursorNextUnique:
return "nextunique"
case CursorPrevious:
return "prev"
case CursorPreviousUnique:
return "prevunique"
default:
return "next"
}
}
func (d CursorDirection) jsValue() safejs.Value {
return cursorDirectionCache.Value(d.String())
}
// Cursor represents a cursor for traversing or iterating over multiple records in a Database
type Cursor struct {
txn *Transaction
jsCursor safejs.Value
iterated bool // set to true when an iteration method is called, like Continue
}
func wrapCursor(txn *Transaction, jsCursor safejs.Value) *Cursor {
if txn == nil {
txn = (*Transaction)(nil)
}
return &Cursor{
txn: txn,
jsCursor: jsCursor,
}
}
// Source returns the ObjectStore or Index that the cursor is iterating
func (c *Cursor) Source() (objectStore *ObjectStore, index *Index, err error) {
jsSource, err := c.jsCursor.Get("source")
if err != nil {
return
}
if isInstance, _ := jsSource.InstanceOf(jsObjectStore); isInstance {
objectStore = wrapObjectStore(c.txn, jsSource)
} else if isInstance, _ := jsSource.InstanceOf(jsIDBIndex); isInstance {
index = wrapIndex(c.txn, jsSource)
}
return
}
// Direction returns the direction of traversal of the cursor
func (c *Cursor) Direction() (CursorDirection, error) {
direction, err := c.jsCursor.Get("direction")
if err != nil {
return 0, err
}
directionStr, err := direction.String()
return parseCursorDirection(directionStr), err
}
// Key returns the key for the record at the cursor's position. If the cursor is outside its range, this is set to undefined.
func (c *Cursor) Key() (js.Value, error) {
value, err := c.jsCursor.Get("key")
return safejs.Unsafe(value), err
}
// PrimaryKey returns the cursor's current effective primary key. If the cursor is currently being iterated or has iterated outside its range, this is set to undefined.
func (c *Cursor) PrimaryKey() (js.Value, error) {
value, err := c.jsCursor.Get("primaryKey")
return safejs.Unsafe(value), err
}
// Request returns the Request that was used to obtain the cursor.
func (c *Cursor) Request() (*Request, error) {
reqValue, err := c.jsCursor.Get("request")
if err != nil {
return nil, err
}
return wrapRequest(c.txn, reqValue), nil
}
// Advance sets the number of times a cursor should move its position forward.
func (c *Cursor) Advance(count uint) error {
c.iterated = true
_, err := c.jsCursor.Call("advance", count)
return tryAsDOMException(err)
}
// Continue advances the cursor to the next position along its direction.
func (c *Cursor) Continue() error {
c.iterated = true
_, err := c.jsCursor.Call("continue")
return tryAsDOMException(err)
}
// ContinueKey advances the cursor to the next position along its direction.
func (c *Cursor) ContinueKey(key js.Value) error {
c.iterated = true
_, err := c.jsCursor.Call("continue", key)
return tryAsDOMException(err)
}
// ContinuePrimaryKey sets the cursor to the given index key and primary key given as arguments. Returns an error if the source is not an index.
func (c *Cursor) ContinuePrimaryKey(key, primaryKey js.Value) error {
c.iterated = true
_, err := c.jsCursor.Call("continuePrimaryKey", key, primaryKey)
return tryAsDOMException(err)
}
// Delete returns an AckRequest, and, in a separate thread, deletes the record at the cursor's position, without changing the cursor's position. This can be used to delete specific records.
func (c *Cursor) Delete() (*AckRequest, error) {
reqValue, err := c.jsCursor.Call("delete")
if err != nil {
return nil, tryAsDOMException(err)
}
req := wrapRequest(c.txn, reqValue)
return newAckRequest(req), nil
}
// Update returns a Request, and, in a separate thread, updates the value at the current position of the cursor in the object store. This can be used to update specific records.
func (c *Cursor) Update(value js.Value) (*Request, error) {
reqValue, err := c.jsCursor.Call("update", value)
if err != nil {
return nil, tryAsDOMException(err)
}
return wrapRequest(c.txn, reqValue), nil
}
// CursorWithValue represents a cursor for traversing or iterating over multiple records in a database. It is the same as the Cursor, except that it includes the value property.
type CursorWithValue struct {
*Cursor
}
func newCursorWithValue(cursor *Cursor) *CursorWithValue {
return &CursorWithValue{cursor}
}
func wrapCursorWithValue(txn *Transaction, jsCursor safejs.Value) *CursorWithValue {
return newCursorWithValue(wrapCursor(txn, jsCursor))
}
// Value returns the value of the current cursor
func (c *CursorWithValue) Value() (js.Value, error) {
value, err := c.jsCursor.Get("value")
return safejs.Unsafe(value), err
}