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
612 lines
21 KiB
Go
612 lines
21 KiB
Go
package storage
|
|
|
|
import (
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
|
|
"fyne.io/fyne/v2"
|
|
"fyne.io/fyne/v2/storage/repository"
|
|
)
|
|
|
|
// EqualURI returns true if the two URIs are equal.
|
|
//
|
|
// Since: 2.6
|
|
func EqualURI(t1, t2 fyne.URI) bool {
|
|
return repository.EqualURI(t1, t2)
|
|
}
|
|
|
|
// NewFileURI creates a new URI from the given file path.
|
|
// Relative paths will be converted to absolute using filepath.Abs if required.
|
|
func NewFileURI(fpath string) fyne.URI {
|
|
if !(path.IsAbs(fpath) || runtime.GOOS == "windows" && filepath.IsAbs(fpath)) {
|
|
absolute, err := filepath.Abs(fpath)
|
|
if err == nil {
|
|
fpath = absolute
|
|
}
|
|
}
|
|
|
|
return repository.NewFileURI(fpath)
|
|
}
|
|
|
|
// NewURI creates a new URI from the given string representation. This could be
|
|
// a URI from an external source or one saved from URI.String()
|
|
//
|
|
// Deprecated: use ParseURI instead
|
|
func NewURI(s string) fyne.URI {
|
|
u, _ := ParseURI(s)
|
|
return u
|
|
}
|
|
|
|
// ParseURI creates a new URI instance by parsing a URI string.
|
|
//
|
|
// Parse URI will parse up to the first ':' present in the URI string to
|
|
// extract the scheme, and then delegate further parsing to the registered
|
|
// repository for the given scheme. If no repository is registered for that
|
|
// scheme, the URI is parsed on a best-effort basis using net/url.
|
|
//
|
|
// As a special exception, URIs beginning with 'file:' are always parsed using
|
|
// NewFileURI(), which will correctly handle back-slashes appearing in the URI
|
|
// path component on Windows.
|
|
//
|
|
// Since: 2.0
|
|
func ParseURI(s string) (fyne.URI, error) {
|
|
return repository.ParseURI(s)
|
|
}
|
|
|
|
// Parent returns a URI referencing the parent resource of the resource
|
|
// referenced by the URI. For example, the Parent() of 'file://foo/bar.baz' is
|
|
// 'file://foo'. The URI which is returned will be listable.
|
|
//
|
|
// NOTE: it is not a given that Parent() return a parent URI with the same
|
|
// Scheme(), though this will normally be the case.
|
|
//
|
|
// This can fail in several ways:
|
|
//
|
|
// - If the URI refers to a filesystem root, then the Parent() implementation
|
|
// must return (nil, URIRootError).
|
|
//
|
|
// - If the URI refers to a resource which does not exist in a hierarchical
|
|
// context (e.g. the URI references something which does not have a
|
|
// semantically meaningful "parent"), the Parent() implementation may return
|
|
// an error.
|
|
//
|
|
// - If determining the parent of the referenced resource requires
|
|
// interfacing with some external system, failures may propagate
|
|
// through the Parent() implementation. For example if determining
|
|
// the parent of a file:// URI requires reading information from
|
|
// the filesystem, it could fail with a permission error.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// HierarchicalRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// NOTE: since v2.0.0, Parent() is backed by the repository system - this
|
|
// function is a helper which calls into an appropriate repository instance for
|
|
// the scheme of the URI it is given.
|
|
//
|
|
// Since: 1.4
|
|
func Parent(u fyne.URI) (fyne.URI, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hrepo, ok := repo.(repository.HierarchicalRepository)
|
|
if !ok {
|
|
return nil, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return hrepo.Parent(u)
|
|
}
|
|
|
|
// Child returns a URI referencing a resource nested hierarchically below the
|
|
// given URI, identified by a string. For example, the child with the string
|
|
// component 'quux' of 'file://foo/bar' is 'file://foo/bar/quux'.
|
|
//
|
|
// This can fail in several ways:
|
|
//
|
|
// - If the URI refers to a resource which does not exist in a hierarchical
|
|
// context (e.g. the URI references something which does not have a
|
|
// semantically meaningful "child"), the Child() implementation may return an
|
|
// error.
|
|
//
|
|
// - If generating a reference to a child of the referenced resource requires
|
|
// interfacing with some external system, failures may propagate through the
|
|
// Child() implementation. It is expected that this case would occur very
|
|
// rarely if ever.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// HierarchicalRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// NOTE: since v2.0.0, Child() is backed by the repository system - this
|
|
// function is a helper which calls into an appropriate repository instance for
|
|
// the scheme of the URI it is given.
|
|
//
|
|
// Since: 1.4
|
|
func Child(u fyne.URI, component string) (fyne.URI, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
hrepo, ok := repo.(repository.HierarchicalRepository)
|
|
if !ok {
|
|
return nil, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return hrepo.Child(u, component)
|
|
}
|
|
|
|
// Exists determines if the resource referenced by the URI exists.
|
|
//
|
|
// This can fail in several ways:
|
|
//
|
|
// - If checking the existence of a resource requires interfacing with some
|
|
// external system, then failures may propagate through Exists(). For
|
|
// example, checking the existence of a resource requires reading a directory
|
|
// may result in a permissions error.
|
|
//
|
|
// It is understood that a non-nil error value signals that the existence or
|
|
// non-existence of the resource cannot be determined and is undefined.
|
|
//
|
|
// NOTE: since v2.0.0, Exists is backed by the repository system - this function
|
|
// calls into a scheme-specific implementation from a registered repository.
|
|
//
|
|
// Exists may call into either a generic implementation, or into a
|
|
// scheme-specific implementation depending on which storage repositories have
|
|
// been registered.
|
|
//
|
|
// Since: 1.4
|
|
func Exists(u fyne.URI) (bool, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return repo.Exists(u)
|
|
}
|
|
|
|
// Delete destroys, deletes, or otherwise removes the resource referenced
|
|
// by the URI.
|
|
//
|
|
// This can fail in several ways:
|
|
//
|
|
// - If removing the resource requires interfacing with some external system,
|
|
// failures may propagate through Destroy(). For example, deleting a file may
|
|
// fail with a permissions error.
|
|
//
|
|
// - If the referenced resource does not exist, attempting to destroy it should
|
|
// throw an error.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// WritableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// Delete is backed by the repository system - this function calls
|
|
// into a scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func Delete(u fyne.URI) error {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
wrepo, ok := repo.(repository.WritableRepository)
|
|
if !ok {
|
|
return repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return wrepo.Delete(u)
|
|
}
|
|
|
|
// DeleteAll destroys, deletes, or otherwise removes the resource referenced
|
|
// by the URI and any child resources for listable URIs.
|
|
//
|
|
// DeleteAll is backed by the repository system - this function calls
|
|
// into a scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.7
|
|
func DeleteAll(u fyne.URI) error {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
drepo, ok := repo.(repository.DeleteAllRepository)
|
|
if !ok {
|
|
return repository.GenericDeleteAll(u)
|
|
}
|
|
|
|
return drepo.DeleteAll(u)
|
|
}
|
|
|
|
// Reader returns URIReadCloser set up to read from the resource that the
|
|
// URI references.
|
|
//
|
|
// This method can fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to read the
|
|
// referenced resource.
|
|
//
|
|
// - This URI scheme could represent some resources that can be read,
|
|
// but this particular URI references a resources that is not
|
|
// something that can be read.
|
|
//
|
|
// - Attempting to set up the reader depended on a lower level
|
|
// operation such as a network or filesystem access that has failed
|
|
// in some way.
|
|
//
|
|
// Reader is backed by the repository system - this function calls
|
|
// into a scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func Reader(u fyne.URI) (fyne.URIReadCloser, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return repo.Reader(u)
|
|
}
|
|
|
|
// CanRead determines if a given URI could be written to using the Reader()
|
|
// method. It is preferred to check if a URI is readable using this method
|
|
// before calling Reader(), because the underlying operations required to
|
|
// attempt to read and then report an error may be slower than the operations
|
|
// needed to test if a URI is readable. Keep in mind however that even if
|
|
// CanRead returns true, you must still do appropriate error handling for
|
|
// Reader(), as the underlying filesystem may have changed since you called
|
|
// CanRead.
|
|
//
|
|
// The non-existence of a resource should not be treated as an error. In other
|
|
// words, a Repository implementation which for some URI u returns false, nil
|
|
// for Exists(u), CanRead(u) should also return false, nil.
|
|
//
|
|
// CanRead is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func CanRead(u fyne.URI) (bool, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return repo.CanRead(u)
|
|
}
|
|
|
|
// Writer returns URIWriteCloser set up to write to the resource that the
|
|
// URI references.
|
|
//
|
|
// Writing to a non-extant resource should create that resource if possible
|
|
// (and if not possible, this should be reflected in the return of CanWrite()).
|
|
// Writing to an extant resource should overwrite it in-place. At present, this
|
|
// API does not provide a mechanism for appending to an already-extant
|
|
// resource, except for reading it in and writing all the data back out.
|
|
//
|
|
// This method can fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to write to the
|
|
// referenced resource.
|
|
//
|
|
// - This URI scheme could represent some resources that can be
|
|
// written, but this particular URI references a resources that is
|
|
// not something that can be written.
|
|
//
|
|
// - Attempting to set up the writer depended on a lower level
|
|
// operation such as a network or filesystem access that has failed
|
|
// in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// WritableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// Writer is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func Writer(u fyne.URI) (fyne.URIWriteCloser, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
wrepo, ok := repo.(repository.WritableRepository)
|
|
if !ok {
|
|
return nil, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return wrepo.Writer(u)
|
|
}
|
|
|
|
// Appender returns URIWriteCloser set up to write to the resource that the
|
|
// URI references without truncating it first
|
|
//
|
|
// Writing to a non-extant resource should create that resource if possible
|
|
// (and if not possible, this should be reflected in the return of CanWrite()).
|
|
// Writing to an extant resource should NOT overwrite it in-place.
|
|
//
|
|
// This method can fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to write to the
|
|
// referenced resource.
|
|
//
|
|
// - This URI scheme could represent some resources that can be
|
|
// written, but this particular URI references a resources that is
|
|
// not something that can be written.
|
|
//
|
|
// - Attempting to set up the writer depended on a lower level
|
|
// operation such as a network or filesystem access that has failed
|
|
// in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// AppendableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// Appender is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.6
|
|
func Appender(u fyne.URI) (fyne.URIWriteCloser, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
wrepo, ok := repo.(repository.AppendableRepository)
|
|
if !ok {
|
|
return nil, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return wrepo.Appender(u)
|
|
}
|
|
|
|
// CanWrite determines if a given URI could be written to using the Writer()
|
|
// method. It is preferred to check if a URI is writable using this method
|
|
// before calling Writer(), because the underlying operations required to
|
|
// attempt to write and then report an error may be slower than the operations
|
|
// needed to test if a URI is writable. Keep in mind however that even if
|
|
// CanWrite returns true, you must still do appropriate error handling for
|
|
// Writer(), as the underlying filesystem may have changed since you called
|
|
// CanWrite.
|
|
|
|
// CanWrite is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func CanWrite(u fyne.URI) (bool, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
wrepo, ok := repo.(repository.WritableRepository)
|
|
if !ok {
|
|
return false, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return wrepo.CanWrite(u)
|
|
}
|
|
|
|
// Copy given two URIs, 'src', and 'dest' both of the same scheme, will copy
|
|
// one to the other. If the source and destination are of different schemes,
|
|
// then the Copy implementation for the storage repository registered to the
|
|
// scheme of the source will be used. Implementations are recommended to use
|
|
// repository.GenericCopy() as a fail-over in the case that they do not
|
|
// understand how to operate on the scheme of the destination URI. However, the
|
|
// behavior of calling Copy() on URIs of non-matching schemes is ultimately
|
|
// defined by the storage repository registered to the scheme of the source
|
|
// URI.
|
|
//
|
|
// This method may fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to perform the
|
|
// copy operation.
|
|
//
|
|
// - This URI scheme could represent some resources that can be copied,
|
|
// but either the source, destination, or both are not resources
|
|
// that support copying.
|
|
//
|
|
// - Performing the copy operation depended on a lower level operation
|
|
// such as network or filesystem access that has failed in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// CopyableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// Copy is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func Copy(source fyne.URI, destination fyne.URI) error {
|
|
repo, err := repository.ForURI(source)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
crepo, ok := repo.(repository.CopyableRepository)
|
|
if !ok {
|
|
return repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return crepo.Copy(source, destination)
|
|
}
|
|
|
|
// Move returns a method that given two URIs, 'src' and 'dest' both of the same
|
|
// scheme this will move src to dest. This means the resource referenced by
|
|
// src will be copied into the resource referenced by dest, and the resource
|
|
// referenced by src will no longer exist after the operation is complete.
|
|
//
|
|
// If the source and destination are of different schemes, then the Move
|
|
// implementation for the storage repository registered to the scheme of the
|
|
// source will be used. Implementations are recommended to use
|
|
// repository.GenericMove() as a fail-over in the case that they do not
|
|
// understand how to operate on the scheme of the destination URI. However, the
|
|
// behavior of calling Move() on URIs of non-matching schemes is ultimately
|
|
// defined by the storage repository registered to the scheme of the source
|
|
// URI.
|
|
//
|
|
// This method may fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to perform the
|
|
// rename operation.
|
|
//
|
|
// - This URI scheme could represent some resources that can be renamed,
|
|
// but either the source, destination, or both are not resources
|
|
// that support renaming.
|
|
//
|
|
// - Performing the rename operation depended on a lower level operation
|
|
// such as network or filesystem access that has failed in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// MovableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// Move is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func Move(source fyne.URI, destination fyne.URI) error {
|
|
repo, err := repository.ForURI(source)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mrepo, ok := repo.(repository.MovableRepository)
|
|
if !ok {
|
|
return repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return mrepo.Move(source, destination)
|
|
}
|
|
|
|
// CanList will determine if the URI is listable or not.
|
|
//
|
|
// This method may fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to check if the
|
|
// URI supports listing.
|
|
//
|
|
// - This URI scheme could represent some resources that can be listed,
|
|
// but this specific URI is not one of them (e.g. a file on a
|
|
// filesystem, as opposed to a directory).
|
|
//
|
|
// - Checking for listability depended on a lower level operation
|
|
// such as network or filesystem access that has failed in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// ListableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// CanList is backed by the repository system - this function calls into a
|
|
// scheme-specific implementation from a registered repository.
|
|
//
|
|
// Since: 2.0
|
|
func CanList(u fyne.URI) (bool, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
lrepo, ok := repo.(repository.ListableRepository)
|
|
if !ok {
|
|
return false, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return lrepo.CanList(u)
|
|
}
|
|
|
|
// List returns a list of URIs that reference resources which are nested below
|
|
// the resource referenced by the argument. For example, listing a directory on
|
|
// a filesystem should return a list of files and directories it contains.
|
|
//
|
|
// This method may fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to obtain a
|
|
// listing for the given URI.
|
|
//
|
|
// - This URI scheme could represent some resources that can be listed,
|
|
// but this specific URI is not one of them (e.g. a file on a
|
|
// filesystem, as opposed to a directory). This can be tested in advance
|
|
// using the Listable() function.
|
|
//
|
|
// - Obtaining the listing depended on a lower level operation such as
|
|
// network or filesystem access that has failed in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// ListableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// List is backed by the repository system - this function either calls into a
|
|
// scheme-specific implementation from a registered repository, or fails with a
|
|
// URIOperationNotSupported error.
|
|
//
|
|
// Since: 2.0
|
|
func List(u fyne.URI) ([]fyne.URI, error) {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
lrepo, ok := repo.(repository.ListableRepository)
|
|
if !ok {
|
|
return nil, repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return lrepo.List(u)
|
|
}
|
|
|
|
// CreateListable creates a new listable resource referenced by the given URI.
|
|
// CreateListable will error if the URI already references an extant resource.
|
|
// This method is used for storage repositories where listable resources are of
|
|
// a different underlying type than other resources - for example, in a typical
|
|
// filesystem ('file://'), CreateListable() corresponds to directory creation,
|
|
// and Writer() implies file creation for non-extant operands.
|
|
//
|
|
// For storage repositories where listable and non-listable resources are the
|
|
// of the same underlying type, CreateListable should be equivalent to calling
|
|
// Writer(), writing zero bytes, and then closing the `URIWriteCloser - in
|
|
// filesystem terms, the same as calling 'touch;'.
|
|
//
|
|
// Storage repositories which support listing, but not creation of listable
|
|
// objects may return repository.ErrOperationNotSupported.
|
|
//
|
|
// CreateListable should generally fail if the parent of its operand does not
|
|
// exist, however this can vary by the implementation details of the specific
|
|
// storage repository. In filesystem terms, this function is "mkdir" not "mkdir
|
|
// -p".
|
|
//
|
|
// This method may fail in several ways:
|
|
//
|
|
// - Different permissions or credentials are required to create the requested
|
|
// resource.
|
|
//
|
|
// - Creating the resource depended on a lower level operation such as network
|
|
// or filesystem access that has failed in some way.
|
|
//
|
|
// - If the scheme of the given URI does not have a registered
|
|
// ListableRepository instance, then this method will fail with a
|
|
// repository.ErrOperationNotSupported.
|
|
//
|
|
// CreateListable is backed by the repository system - this function either
|
|
// calls into a scheme-specific implementation from a registered repository, or
|
|
// fails with a URIOperationNotSupported error.
|
|
//
|
|
// Since: 2.0
|
|
func CreateListable(u fyne.URI) error {
|
|
repo, err := repository.ForURI(u)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
lrepo, ok := repo.(repository.ListableRepository)
|
|
if !ok {
|
|
return repository.ErrOperationNotSupported
|
|
}
|
|
|
|
return lrepo.CreateListable(u)
|
|
}
|