101 lines
2.5 KiB
Go
101 lines
2.5 KiB
Go
|
package video
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"io"
|
||
|
"os"
|
||
|
|
||
|
"github.com/photoprism/photoprism/pkg/fs"
|
||
|
)
|
||
|
|
||
|
// Reader reads an existing file from an offset until the end.
|
||
|
type Reader struct {
|
||
|
fileName string
|
||
|
file *os.File
|
||
|
offset int64
|
||
|
}
|
||
|
|
||
|
// NewReader creates a new Reader.
|
||
|
func NewReader(fileName string, offset int64) (*Reader, error) {
|
||
|
// Check if the file exists.
|
||
|
if !fs.FileExists(fileName) {
|
||
|
return nil, errors.New("file not found")
|
||
|
}
|
||
|
|
||
|
// Open file for reading.
|
||
|
file, err := os.Open(fileName)
|
||
|
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
// Ensure that the offset is positive and we are starting at the right position.
|
||
|
if offset < 0 {
|
||
|
offset = 0
|
||
|
} else if offset > 0 {
|
||
|
if _, seekErr := file.Seek(offset, io.SeekStart); seekErr != nil {
|
||
|
_ = file.Close()
|
||
|
return nil, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Create new reader and return it.
|
||
|
return &Reader{fileName: fileName, file: file, offset: int64(offset)}, nil
|
||
|
}
|
||
|
|
||
|
// Read reads up to len(p) bytes into p. It returns the number of bytes read and any error encountered.
|
||
|
func (r *Reader) Read(p []byte) (n int, err error) {
|
||
|
return r.file.Read(p)
|
||
|
}
|
||
|
|
||
|
// Close closes the file after reading.
|
||
|
func (r *Reader) Close() error {
|
||
|
r.fileName = ""
|
||
|
r.offset = 0
|
||
|
return r.file.Close()
|
||
|
}
|
||
|
|
||
|
// ReadSeeker reads an existing file from an offset until the end.
|
||
|
type ReadSeeker struct {
|
||
|
file io.ReadSeeker
|
||
|
offset int64
|
||
|
}
|
||
|
|
||
|
// NewReadSeeker creates a new ReadSeeker.
|
||
|
func NewReadSeeker(file io.ReadSeeker, offset int64) *ReadSeeker {
|
||
|
// Ensure that the offset is positive.
|
||
|
if offset < 0 {
|
||
|
offset = 0
|
||
|
}
|
||
|
|
||
|
return &ReadSeeker{
|
||
|
file: file,
|
||
|
offset: offset,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Read reads up to len(p) bytes into p. It returns the number of bytes read and any error encountered.
|
||
|
func (r *ReadSeeker) Read(p []byte) (n int, err error) {
|
||
|
return r.file.Read(p)
|
||
|
}
|
||
|
|
||
|
// Seek sets the offset for the next Read or Write to offset, interpreted according to whence:
|
||
|
// - SeekStart means relative to the start of the file
|
||
|
// - SeekCurrent means relative to the current offset
|
||
|
// - SeekEnd means relative to the end (for example, offset = -2 specifies the penultimate byte of the file)
|
||
|
//
|
||
|
// Seek returns the new offset relative to the start of the file or an error, if any.
|
||
|
// Seeking to an offset before the start of the file is an error.
|
||
|
func (r *ReadSeeker) Seek(offset int64, whence int) (pos int64, err error) {
|
||
|
switch whence {
|
||
|
case io.SeekStart:
|
||
|
pos, err = r.file.Seek(offset+r.offset, whence)
|
||
|
case io.SeekCurrent, io.SeekEnd:
|
||
|
pos, err = r.file.Seek(offset, whence)
|
||
|
default:
|
||
|
return 0, errors.New("unknown whence")
|
||
|
}
|
||
|
|
||
|
return pos - r.offset, err
|
||
|
}
|