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
197 lines
5.9 KiB
Go
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
|
|
}
|