Support using the custom video serving endpoint even if you don't use object storage (#2924)
* feat(video): refactor video serving endpoint It can now be used without an object storage provider. Closes #2785 * fix: remove debug log
This commit is contained in:
@@ -6,13 +6,15 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/transcoder"
|
||||
)
|
||||
|
||||
// LocalStorage represents an instance of the local storage provider for HLS video.
|
||||
type LocalStorage struct {
|
||||
// Cleanup old public HLS content every N min from the webroot.
|
||||
onlineCleanupTicker *time.Ticker
|
||||
onlineCleanupTicker *time.Ticker
|
||||
customVideoServingEndpoint string
|
||||
}
|
||||
|
||||
// NewLocalStorage returns a new LocalStorage instance.
|
||||
@@ -22,6 +24,10 @@ func NewLocalStorage() *LocalStorage {
|
||||
|
||||
// Setup configures this storage provider.
|
||||
func (s *LocalStorage) Setup() error {
|
||||
if data.GetVideoServingEndpoint() != "" {
|
||||
s.customVideoServingEndpoint = data.GetVideoServingEndpoint()
|
||||
}
|
||||
|
||||
// NOTE: This cleanup timer will have to be disabled to support recordings in the future
|
||||
// as all HLS segments have to be publicly available on disk to keep a recording of them.
|
||||
s.onlineCleanupTicker = time.NewTicker(1 * time.Minute)
|
||||
@@ -50,7 +56,12 @@ func (s *LocalStorage) VariantPlaylistWritten(localFilePath string) {
|
||||
|
||||
// MasterPlaylistWritten is called when the master hls playlist is written.
|
||||
func (s *LocalStorage) MasterPlaylistWritten(localFilePath string) {
|
||||
if _, err := s.Save(localFilePath, 0); err != nil {
|
||||
if s.customVideoServingEndpoint != "" {
|
||||
// Rewrite the playlist to use custom absolute remote URLs
|
||||
if err := rewriteRemotePlaylist(localFilePath, s.customVideoServingEndpoint); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
} else if _, err := s.Save(localFilePath, 0); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
}
|
||||
|
||||
36
core/storageproviders/rewriteLocalPlaylist.go
Normal file
36
core/storageproviders/rewriteLocalPlaylist.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package storageproviders
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafov/m3u8"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/playlist"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// rewriteRemotePlaylist will take a local playlist and rewrite it to have absolute URLs to remote locations.
|
||||
func rewriteRemotePlaylist(localFilePath, remoteServingEndpoint string) error {
|
||||
f, err := os.Open(localFilePath) // nolint
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
p := m3u8.NewMasterPlaylist()
|
||||
if err := p.DecodeFrom(bufio.NewReader(f), false); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
|
||||
for _, item := range p.Variants {
|
||||
item.URI = remoteServingEndpoint + filepath.Join("/hls", item.URI)
|
||||
}
|
||||
|
||||
publicPath := filepath.Join(config.HLSStoragePath, filepath.Base(localFilePath))
|
||||
|
||||
newPlaylist := p.String()
|
||||
|
||||
return playlist.WritePlaylist(newPlaylist, publicPath)
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package storageproviders
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -11,7 +10,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/playlist"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
@@ -21,8 +19,6 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
|
||||
"github.com/grafov/m3u8"
|
||||
)
|
||||
|
||||
// S3Storage is the s3 implementation of a storage provider.
|
||||
@@ -58,8 +54,9 @@ func (s *S3Storage) Setup() error {
|
||||
log.Trace("Setting up S3 for external storage of video...")
|
||||
|
||||
s3Config := data.GetS3Config()
|
||||
if s3Config.ServingEndpoint != "" {
|
||||
s.host = s3Config.ServingEndpoint
|
||||
customVideoServingEndpoint := data.GetVideoServingEndpoint()
|
||||
if customVideoServingEndpoint != "" {
|
||||
s.host = customVideoServingEndpoint
|
||||
} else {
|
||||
s.host = fmt.Sprintf("%s/%s", s3Config.Endpoint, s3Config.Bucket)
|
||||
}
|
||||
@@ -130,7 +127,7 @@ func (s *S3Storage) VariantPlaylistWritten(localFilePath string) {
|
||||
// MasterPlaylistWritten is called when the master hls playlist is written.
|
||||
func (s *S3Storage) MasterPlaylistWritten(localFilePath string) {
|
||||
// Rewrite the playlist to use absolute remote S3 URLs
|
||||
if err := s.rewriteRemotePlaylist(localFilePath); err != nil {
|
||||
if err := rewriteRemotePlaylist(localFilePath, s.host); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
}
|
||||
@@ -216,26 +213,3 @@ func (s *S3Storage) connectAWS() *session.Session {
|
||||
}
|
||||
return sess
|
||||
}
|
||||
|
||||
// rewriteRemotePlaylist will take a local playlist and rewrite it to have absolute URLs to remote locations.
|
||||
func (s *S3Storage) rewriteRemotePlaylist(filePath string) error {
|
||||
f, err := os.Open(filePath) // nolint
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
p := m3u8.NewMasterPlaylist()
|
||||
if err := p.DecodeFrom(bufio.NewReader(f), false); err != nil {
|
||||
log.Warnln(err)
|
||||
}
|
||||
|
||||
for _, item := range p.Variants {
|
||||
item.URI = s.host + filepath.Join("/hls", item.URI)
|
||||
}
|
||||
|
||||
publicPath := filepath.Join(config.HLSStoragePath, filepath.Base(filePath))
|
||||
|
||||
newPlaylist := p.String()
|
||||
|
||||
return playlist.WritePlaylist(newPlaylist, publicPath)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user