You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.2 KiB
128 lines
3.2 KiB
package storageproviders |
|
|
|
import ( |
|
"os" |
|
"path/filepath" |
|
"sort" |
|
|
|
"github.com/pkg/errors" |
|
log "github.com/sirupsen/logrus" |
|
|
|
"github.com/owncast/owncast/config" |
|
"github.com/owncast/owncast/core/data" |
|
) |
|
|
|
// LocalStorage represents an instance of the local storage provider for HLS video. |
|
type LocalStorage struct { |
|
host string |
|
} |
|
|
|
// NewLocalStorage returns a new LocalStorage instance. |
|
func NewLocalStorage() *LocalStorage { |
|
return &LocalStorage{} |
|
} |
|
|
|
// Setup configures this storage provider. |
|
func (s *LocalStorage) Setup() error { |
|
s.host = data.GetVideoServingEndpoint() |
|
return nil |
|
} |
|
|
|
// SegmentWritten is called when a single segment of video is written. |
|
func (s *LocalStorage) SegmentWritten(localFilePath string) { |
|
if _, err := s.Save(localFilePath, 0); err != nil { |
|
log.Warnln(err) |
|
} |
|
} |
|
|
|
// VariantPlaylistWritten is called when a variant hls playlist is written. |
|
func (s *LocalStorage) VariantPlaylistWritten(localFilePath string) { |
|
if _, err := s.Save(localFilePath, 0); err != nil { |
|
log.Errorln(err) |
|
return |
|
} |
|
} |
|
|
|
// MasterPlaylistWritten is called when the master hls playlist is written. |
|
func (s *LocalStorage) MasterPlaylistWritten(localFilePath string) { |
|
// If we're using a remote serving endpoint, we need to rewrite the master playlist |
|
if s.host != "" { |
|
if err := rewritePlaylistLocations(localFilePath, s.host, ""); err != nil { |
|
log.Warnln(err) |
|
} |
|
} else { |
|
if _, err := s.Save(localFilePath, 0); err != nil { |
|
log.Warnln(err) |
|
} |
|
} |
|
} |
|
|
|
// Save will save a local filepath using the storage provider. |
|
func (s *LocalStorage) Save(filePath string, retryCount int) (string, error) { |
|
return filePath, nil |
|
} |
|
|
|
func (s *LocalStorage) Cleanup() error { |
|
// Determine how many files we should keep on disk |
|
maxNumber := data.GetStreamLatencyLevel().SegmentCount |
|
buffer := 10 |
|
baseDirectory := config.HLSStoragePath |
|
|
|
files, err := getAllFilesRecursive(baseDirectory) |
|
if err != nil { |
|
return errors.Wrap(err, "unable find old video files for cleanup") |
|
} |
|
|
|
// Delete old private HLS files on disk |
|
for directory := range files { |
|
files := files[directory] |
|
if len(files) < maxNumber+buffer { |
|
continue |
|
} |
|
|
|
filesToDelete := files[maxNumber+buffer:] |
|
log.Traceln("Deleting", len(filesToDelete), "old files from", baseDirectory, "for video variant", directory) |
|
|
|
for _, file := range filesToDelete { |
|
fileToDelete := filepath.Join(baseDirectory, directory, file.Name()) |
|
err := os.Remove(fileToDelete) |
|
if err != nil { |
|
return errors.Wrap(err, "unable to delete old video files") |
|
} |
|
} |
|
} |
|
return nil |
|
} |
|
|
|
func getAllFilesRecursive(baseDirectory string) (map[string][]os.FileInfo, error) { |
|
files := make(map[string][]os.FileInfo) |
|
|
|
var directory string |
|
err := filepath.Walk(baseDirectory, func(path string, info os.FileInfo, err error) error { |
|
if err != nil { |
|
return err |
|
} |
|
|
|
if info.IsDir() { |
|
directory = info.Name() |
|
} |
|
|
|
if filepath.Ext(info.Name()) == ".ts" { |
|
files[directory] = append(files[directory], info) |
|
} |
|
|
|
return nil |
|
}) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
// Sort by date so we can delete old files |
|
for directory := range files { |
|
sort.Slice(files[directory], func(i, j int) bool { |
|
return files[directory][i].ModTime().UnixNano() > files[directory][j].ModTime().UnixNano() |
|
}) |
|
} |
|
|
|
return files, nil |
|
}
|
|
|