diff --git a/config/config.go b/config/config.go index af3747e21..d5b2ca144 100644 --- a/config/config.go +++ b/config/config.go @@ -3,8 +3,6 @@ package config import ( "errors" "io/ioutil" - "os/exec" - "strings" "github.com/gabek/owncast/utils" log "github.com/sirupsen/logrus" @@ -13,6 +11,7 @@ import ( //Config contains a reference to the configuration var Config *config +var _default config type config struct { ChatDatabaseFilePath string `yaml:"chatDatabaseFile"` @@ -116,6 +115,10 @@ func (c *config) load(filePath string) error { } func (c *config) verifySettings() error { + if c.VideoSettings.StreamingKey == "" { + return errors.New("No stream key set. Please set one in your config file.") + } + if c.S3.Enabled && c.IPFS.Enabled { return errors.New("s3 and IPFS support cannot be enabled at the same time; choose one") } @@ -137,32 +140,12 @@ func (c *config) verifySettings() error { return nil } -func (c *config) GetFFMpegPath() string { - if c.FFMpegPath != "" { - return c.FFMpegPath - } - - cmd := exec.Command("which", "ffmpeg") - out, err := cmd.CombinedOutput() - if err != nil { - log.Panicln("Unable to determine path to ffmpeg. Please specify it in the config file.") - } - - path := strings.TrimSpace(string(out)) - - // Memoize it for future access - c.FFMpegPath = path - - return path -} - func (c *config) GetVideoSegmentSecondsLength() int { if c.VideoSettings.ChunkLengthInSeconds != 0 { return c.VideoSettings.ChunkLengthInSeconds } - // Default - return 4 + return _default.GetVideoSegmentSecondsLength() } func (c *config) GetPublicHLSSavePath() string { @@ -170,7 +153,7 @@ func (c *config) GetPublicHLSSavePath() string { return c.PublicHLSPath } - return "webroot/hls" + return _default.PublicHLSPath } func (c *config) GetPrivateHLSSavePath() string { @@ -178,7 +161,7 @@ func (c *config) GetPrivateHLSSavePath() string { return c.PrivateHLSPath } - return "hls" + return _default.PrivateHLSPath } func (c *config) GetPublicWebServerPort() int { @@ -186,8 +169,7 @@ func (c *config) GetPublicWebServerPort() int { return c.WebServerPort } - // Default web server port - return 8080 + return _default.WebServerPort } func (c *config) GetMaxNumberOfReferencedSegmentsInPlaylist() int { @@ -195,7 +177,7 @@ func (c *config) GetMaxNumberOfReferencedSegmentsInPlaylist() int { return c.Files.MaxNumberInPlaylist } - return 20 + return _default.GetMaxNumberOfReferencedSegmentsInPlaylist() } func (c *config) GetOfflineContentPath() string { @@ -204,12 +186,29 @@ func (c *config) GetOfflineContentPath() string { } // This is relative to the webroot, not the project root. - return "static/offline.m4v" + return _default.VideoSettings.OfflineContent +} + +func (c *config) GetFFMpegPath() string { + if c.FFMpegPath != "" { + return c.FFMpegPath + } + + return _default.FFMpegPath +} + +func (c *config) GetVideoStreamQualities() []StreamQuality { + if len(c.VideoSettings.StreamQualities) > 0 { + return c.VideoSettings.StreamQualities + } + + return _default.VideoSettings.StreamQualities } //Load tries to load the configuration file func Load(filePath string, versionInfo string) error { Config = new(config) + _default = getDefaults() if err := Config.load(filePath); err != nil { return err @@ -220,8 +219,10 @@ func Load(filePath string, versionInfo string) error { // Defaults // This is relative to the webroot, not the project root. + // Has to be set here instead of pulled from a getter + // since it's serialized to JSON. if Config.InstanceDetails.ExtraInfoFile == "" { - Config.InstanceDetails.ExtraInfoFile = "/static/content.md" + Config.InstanceDetails.ExtraInfoFile = _default.InstanceDetails.ExtraInfoFile } return Config.verifySettings() diff --git a/config/defaults.go b/config/defaults.go new file mode 100644 index 000000000..ded829273 --- /dev/null +++ b/config/defaults.go @@ -0,0 +1,40 @@ +package config + +import ( + "log" + "os/exec" + "strings" +) + +func getDefaults() config { + defaults := config{} + defaults.WebServerPort = 8080 + defaults.FFMpegPath = getDefaultFFMpegPath() + defaults.VideoSettings.ChunkLengthInSeconds = 4 + defaults.Files.MaxNumberInPlaylist = 5 + defaults.PublicHLSPath = "webroot/hls" + defaults.PrivateHLSPath = "hls" + defaults.VideoSettings.OfflineContent = "static/offline.m4v" + defaults.InstanceDetails.ExtraInfoFile = "/static/content.md" + + defaultQuality := StreamQuality{ + IsAudioPassthrough: true, + VideoBitrate: 1200, + EncoderPreset: "veryfast", + } + defaults.VideoSettings.StreamQualities = []StreamQuality{defaultQuality} + + return defaults +} + +func getDefaultFFMpegPath() string { + cmd := exec.Command("which", "ffmpeg") + out, err := cmd.CombinedOutput() + if err != nil { + log.Panicln("Unable to determine path to ffmpeg. Please specify it in the config file.") + } + + path := strings.TrimSpace(string(out)) + + return path +} diff --git a/controllers/status.go b/controllers/status.go index b372651a5..78e62f1dc 100644 --- a/controllers/status.go +++ b/controllers/status.go @@ -13,6 +13,7 @@ func GetStatus(w http.ResponseWriter, r *http.Request) { middleware.EnableCors(&w) status := core.GetStatus() + w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(status) } diff --git a/core/chat/client.go b/core/chat/client.go index 7436336fb..2c5553047 100644 --- a/core/chat/client.go +++ b/core/chat/client.go @@ -111,6 +111,7 @@ func (c *Client) listenRead() { msg.ID = id msg.MessageType = "CHAT" msg.Timestamp = time.Now() + msg.Visible = true if err := websocket.JSON.Receive(c.ws, &msg); err == io.EOF { c.doneCh <- true diff --git a/core/chat/server.go b/core/chat/server.go index 62e9f4bf6..2d3c20afc 100644 --- a/core/chat/server.go +++ b/core/chat/server.go @@ -56,12 +56,6 @@ func (s *server) err(err error) { s.errCh <- err } -func (s *server) sendPastMessages(c *Client) { - for _, msg := range s.Messages { - c.Write(msg) - } -} - func (s *server) sendAll(msg models.ChatMessage) { for _, c := range s.Clients { c.Write(msg) @@ -104,7 +98,6 @@ func (s *server) Listen() { s.Clients[c.id] = c s.listener.ClientAdded(c.id) - s.sendPastMessages(c) // remove a client case c := <-s.delCh: diff --git a/doc/config-example-full.yaml b/doc/config-example-full.yaml index ac7bca6dc..9edcaf821 100644 --- a/doc/config-example-full.yaml +++ b/doc/config-example-full.yaml @@ -55,7 +55,8 @@ videoSettings: audioPassthrough: true # The slower the preset the higher quality the video is. # Select a preset from https://trac.ffmpeg.org/wiki/Encode/H.264 - encoderPreset: superfast + # "superfast" and "ultrafast" are generally not recommended since they look bad. + encoderPreset: veryfast - medium: videoBitrate: 800 diff --git a/webroot/js/app.js b/webroot/js/app.js index 3bde2eef5..06a38206f 100644 --- a/webroot/js/app.js +++ b/webroot/js/app.js @@ -85,6 +85,8 @@ class Owncast { onError: this.handlePlayerError, }); this.player.init(); + + this.getChatHistory(); }; setConfigData(data) { @@ -131,17 +133,21 @@ class Owncast { return; } const message = new Message(model); - const existing = this.vueApp.messages.filter(function (item) { - return item.id === message.id; - }) - if (existing.length === 0 || !existing) { - this.vueApp.messages = [...this.vueApp.messages, message]; - } + this.addMessage(message); }; this.websocket = ws; this.messagingInterface.setWebsocket(this.websocket); }; + addMessage(message) { + const existing = this.vueApp.messages.filter(function (item) { + return item.id === message.id; + }) + if (existing.length === 0 || !existing) { + this.vueApp.messages = [...this.vueApp.messages, message]; + } + } + // fetch /config data getConfig() { fetch(URL_CONFIG) @@ -275,4 +281,18 @@ class Owncast { this.handleOfflineMode(); // stop timers? }; + + async getChatHistory() { + const url = "/chat"; + const response = await fetch(url); + const data = await response.json(); + const messages = data.map(function (message) { + return new Message(message); + }) + this.setChatHistory(messages); + } + + setChatHistory(messages) { + this.vueApp.messages = messages; + } }; diff --git a/webroot/js/message.js b/webroot/js/message.js index 8d36188f6..85a6aab4e 100644 --- a/webroot/js/message.js +++ b/webroot/js/message.js @@ -78,6 +78,7 @@ class MessagingInterface { window.addEventListener("orientationchange", setVHvar); this.tagAppContainer.classList.add('touch-screen'); } + } setWebsocket(socket) { diff --git a/webroot/js/utils.js b/webroot/js/utils.js index 15cb657ac..4bd224b63 100644 --- a/webroot/js/utils.js +++ b/webroot/js/utils.js @@ -32,6 +32,9 @@ const VIDEO_SRC = { const VIDEO_OPTIONS = { autoplay: false, liveui: true, // try this + liveTracker: { + trackingThreshold: 0, + }, sources: [VIDEO_SRC], };