owncast/playlistMonitor.go

122 lines
3.4 KiB
Go
Raw Normal View History

2020-05-30 04:08:33 +03:00
package main
import (
"io/ioutil"
2020-06-02 02:53:31 +03:00
"path"
2020-05-30 04:08:33 +03:00
"path/filepath"
2020-06-09 11:52:15 +03:00
"strconv"
2020-05-30 04:08:33 +03:00
"time"
2020-06-02 02:53:31 +03:00
log "github.com/sirupsen/logrus"
2020-05-30 04:08:33 +03:00
"github.com/radovskyb/watcher"
)
2020-06-09 11:52:15 +03:00
type Segment struct {
VariantIndex int // The bitrate variant
FullDiskPath string // Where it lives on disk
RelativeUploadPath string // Path it should have remotely
RemoteID string // Used for IPFS
}
type Variant struct {
VariantIndex int
Segments []Segment
}
func (v *Variant) getSegmentForFilename(filename string) *Segment {
for _, segment := range v.Segments {
if path.Base(segment.FullDiskPath) == filename {
return &segment
}
}
return nil
}
func getSegmentFromPath(fullDiskPath string) Segment {
segment := Segment{}
segment.FullDiskPath = fullDiskPath
segment.RelativeUploadPath = getRelativePathFromAbsolutePath(fullDiskPath)
index, error := strconv.Atoi(segment.RelativeUploadPath[0:1])
verifyError(error)
segment.VariantIndex = index
return segment
}
func getVariantIndexFromPath(fullDiskPath string) int {
index, error := strconv.Atoi(fullDiskPath[0:1])
verifyError(error)
return index
}
var variants []Variant
2020-05-30 04:08:33 +03:00
func monitorVideoContent(pathToMonitor string, configuration Config, storage ChunkStorage) {
2020-06-09 11:52:15 +03:00
// Create structures to store the segments for the different stream variants
variants = make([]Variant, len(configuration.VideoSettings.StreamQualities))
for index := range variants {
variants[index] = Variant{index, make([]Segment, 0)}
}
log.Printf("Using %s for storing files with %d variants...\n", pathToMonitor, len(variants))
2020-06-02 02:53:31 +03:00
2020-05-30 04:08:33 +03:00
w := watcher.New()
go func() {
for {
select {
case event := <-w.Event:
2020-06-09 11:52:15 +03:00
relativePath := getRelativePathFromAbsolutePath(event.Path)
// Ignore removals
if event.Op == watcher.Remove {
2020-05-30 04:08:33 +03:00
continue
}
2020-06-09 11:52:15 +03:00
// fmt.Println(event.Op, relativePath)
2020-06-03 11:34:05 +03:00
2020-06-09 11:52:15 +03:00
// Handle updates to the master playlist by copying it to webroot
if relativePath == path.Join(configuration.PrivateHLSPath, "stream.m3u8") {
copy(event.Path, path.Join(configuration.PublicHLSPath, "stream.m3u8"))
// Handle updates to playlists, but not the master playlist
} else if filepath.Ext(event.Path) == ".m3u8" {
variantIndex := getVariantIndexFromPath(relativePath)
variant := variants[variantIndex]
2020-06-02 02:53:31 +03:00
2020-05-30 04:08:33 +03:00
playlistBytes, err := ioutil.ReadFile(event.Path)
verifyError(err)
playlistString := string(playlistBytes)
2020-06-09 11:52:15 +03:00
// fmt.Println("Rewriting playlist", relativePath, "to", path.Join(configuration.PublicHLSPath, relativePath))
2020-06-09 11:52:15 +03:00
playlistString = storage.GenerateRemotePlaylist(playlistString, variant)
2020-06-09 11:52:15 +03:00
writePlaylist(playlistString, path.Join(configuration.PublicHLSPath, relativePath))
2020-05-30 04:08:33 +03:00
} else if filepath.Ext(event.Path) == ".ts" {
2020-06-09 11:52:15 +03:00
segment := getSegmentFromPath(event.Path)
newObjectPath := storage.Save(path.Join(configuration.PrivateHLSPath, segment.RelativeUploadPath))
segment.RemoteID = newObjectPath
// fmt.Println("Uploaded", segment.RelativeUploadPath, "as", newObjectPath)
variants[segment.VariantIndex].Segments = append(variants[segment.VariantIndex].Segments, segment)
2020-05-30 04:08:33 +03:00
}
case err := <-w.Error:
log.Fatalln(err)
case <-w.Closed:
return
}
}
}()
2020-06-09 11:52:15 +03:00
// Watch the hls segment storage folder recursively for changes.
if err := w.AddRecursive(pathToMonitor); err != nil {
2020-05-30 04:08:33 +03:00
log.Fatalln(err)
}
if err := w.Start(time.Millisecond * 100); err != nil {
2020-05-30 04:08:33 +03:00
log.Fatalln(err)
}
}