Merge branch 'master' into 0718-refactor-touchscreenlayout
This commit is contained in:
@@ -3,8 +3,6 @@ package config
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gabek/owncast/utils"
|
"github.com/gabek/owncast/utils"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
@@ -13,6 +11,7 @@ import (
|
|||||||
|
|
||||||
//Config contains a reference to the configuration
|
//Config contains a reference to the configuration
|
||||||
var Config *config
|
var Config *config
|
||||||
|
var _default config
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
ChatDatabaseFilePath string `yaml:"chatDatabaseFile"`
|
ChatDatabaseFilePath string `yaml:"chatDatabaseFile"`
|
||||||
@@ -116,6 +115,10 @@ func (c *config) load(filePath string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) verifySettings() 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 {
|
if c.S3.Enabled && c.IPFS.Enabled {
|
||||||
return errors.New("s3 and IPFS support cannot be enabled at the same time; choose one")
|
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
|
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 {
|
func (c *config) GetVideoSegmentSecondsLength() int {
|
||||||
if c.VideoSettings.ChunkLengthInSeconds != 0 {
|
if c.VideoSettings.ChunkLengthInSeconds != 0 {
|
||||||
return c.VideoSettings.ChunkLengthInSeconds
|
return c.VideoSettings.ChunkLengthInSeconds
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default
|
return _default.GetVideoSegmentSecondsLength()
|
||||||
return 4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) GetPublicHLSSavePath() string {
|
func (c *config) GetPublicHLSSavePath() string {
|
||||||
@@ -170,7 +153,7 @@ func (c *config) GetPublicHLSSavePath() string {
|
|||||||
return c.PublicHLSPath
|
return c.PublicHLSPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return "webroot/hls"
|
return _default.PublicHLSPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) GetPrivateHLSSavePath() string {
|
func (c *config) GetPrivateHLSSavePath() string {
|
||||||
@@ -178,7 +161,7 @@ func (c *config) GetPrivateHLSSavePath() string {
|
|||||||
return c.PrivateHLSPath
|
return c.PrivateHLSPath
|
||||||
}
|
}
|
||||||
|
|
||||||
return "hls"
|
return _default.PrivateHLSPath
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) GetPublicWebServerPort() int {
|
func (c *config) GetPublicWebServerPort() int {
|
||||||
@@ -186,8 +169,7 @@ func (c *config) GetPublicWebServerPort() int {
|
|||||||
return c.WebServerPort
|
return c.WebServerPort
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default web server port
|
return _default.WebServerPort
|
||||||
return 8080
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) GetMaxNumberOfReferencedSegmentsInPlaylist() int {
|
func (c *config) GetMaxNumberOfReferencedSegmentsInPlaylist() int {
|
||||||
@@ -195,7 +177,7 @@ func (c *config) GetMaxNumberOfReferencedSegmentsInPlaylist() int {
|
|||||||
return c.Files.MaxNumberInPlaylist
|
return c.Files.MaxNumberInPlaylist
|
||||||
}
|
}
|
||||||
|
|
||||||
return 20
|
return _default.GetMaxNumberOfReferencedSegmentsInPlaylist()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) GetOfflineContentPath() string {
|
func (c *config) GetOfflineContentPath() string {
|
||||||
@@ -204,12 +186,29 @@ func (c *config) GetOfflineContentPath() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is relative to the webroot, not the project root.
|
// 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
|
//Load tries to load the configuration file
|
||||||
func Load(filePath string, versionInfo string) error {
|
func Load(filePath string, versionInfo string) error {
|
||||||
Config = new(config)
|
Config = new(config)
|
||||||
|
_default = getDefaults()
|
||||||
|
|
||||||
if err := Config.load(filePath); err != nil {
|
if err := Config.load(filePath); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -220,8 +219,10 @@ func Load(filePath string, versionInfo string) error {
|
|||||||
// Defaults
|
// Defaults
|
||||||
|
|
||||||
// This is relative to the webroot, not the project root.
|
// 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 == "" {
|
if Config.InstanceDetails.ExtraInfoFile == "" {
|
||||||
Config.InstanceDetails.ExtraInfoFile = "/static/content.md"
|
Config.InstanceDetails.ExtraInfoFile = _default.InstanceDetails.ExtraInfoFile
|
||||||
}
|
}
|
||||||
|
|
||||||
return Config.verifySettings()
|
return Config.verifySettings()
|
||||||
|
|||||||
40
config/defaults.go
Normal file
40
config/defaults.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ func GetStatus(w http.ResponseWriter, r *http.Request) {
|
|||||||
middleware.EnableCors(&w)
|
middleware.EnableCors(&w)
|
||||||
|
|
||||||
status := core.GetStatus()
|
status := core.GetStatus()
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
json.NewEncoder(w).Encode(status)
|
json.NewEncoder(w).Encode(status)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ func (c *Client) listenRead() {
|
|||||||
msg.ID = id
|
msg.ID = id
|
||||||
msg.MessageType = "CHAT"
|
msg.MessageType = "CHAT"
|
||||||
msg.Timestamp = time.Now()
|
msg.Timestamp = time.Now()
|
||||||
|
msg.Visible = true
|
||||||
|
|
||||||
if err := websocket.JSON.Receive(c.ws, &msg); err == io.EOF {
|
if err := websocket.JSON.Receive(c.ws, &msg); err == io.EOF {
|
||||||
c.doneCh <- true
|
c.doneCh <- true
|
||||||
|
|||||||
@@ -56,12 +56,6 @@ func (s *server) err(err error) {
|
|||||||
s.errCh <- err
|
s.errCh <- err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) sendPastMessages(c *Client) {
|
|
||||||
for _, msg := range s.Messages {
|
|
||||||
c.Write(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) sendAll(msg models.ChatMessage) {
|
func (s *server) sendAll(msg models.ChatMessage) {
|
||||||
for _, c := range s.Clients {
|
for _, c := range s.Clients {
|
||||||
c.Write(msg)
|
c.Write(msg)
|
||||||
@@ -104,7 +98,6 @@ func (s *server) Listen() {
|
|||||||
s.Clients[c.id] = c
|
s.Clients[c.id] = c
|
||||||
|
|
||||||
s.listener.ClientAdded(c.id)
|
s.listener.ClientAdded(c.id)
|
||||||
s.sendPastMessages(c)
|
|
||||||
|
|
||||||
// remove a client
|
// remove a client
|
||||||
case c := <-s.delCh:
|
case c := <-s.delCh:
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ videoSettings:
|
|||||||
audioPassthrough: true
|
audioPassthrough: true
|
||||||
# The slower the preset the higher quality the video is.
|
# The slower the preset the higher quality the video is.
|
||||||
# Select a preset from https://trac.ffmpeg.org/wiki/Encode/H.264
|
# 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:
|
- medium:
|
||||||
videoBitrate: 800
|
videoBitrate: 800
|
||||||
|
|||||||
@@ -85,6 +85,8 @@ class Owncast {
|
|||||||
onError: this.handlePlayerError,
|
onError: this.handlePlayerError,
|
||||||
});
|
});
|
||||||
this.player.init();
|
this.player.init();
|
||||||
|
|
||||||
|
this.getChatHistory();
|
||||||
};
|
};
|
||||||
|
|
||||||
setConfigData(data) {
|
setConfigData(data) {
|
||||||
@@ -131,17 +133,21 @@ class Owncast {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const message = new Message(model);
|
const message = new Message(model);
|
||||||
const existing = this.vueApp.messages.filter(function (item) {
|
this.addMessage(message);
|
||||||
return item.id === message.id;
|
|
||||||
})
|
|
||||||
if (existing.length === 0 || !existing) {
|
|
||||||
this.vueApp.messages = [...this.vueApp.messages, message];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
this.websocket = ws;
|
this.websocket = ws;
|
||||||
this.messagingInterface.setWebsocket(this.websocket);
|
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
|
// fetch /config data
|
||||||
getConfig() {
|
getConfig() {
|
||||||
fetch(URL_CONFIG)
|
fetch(URL_CONFIG)
|
||||||
@@ -275,4 +281,18 @@ class Owncast {
|
|||||||
this.handleOfflineMode();
|
this.handleOfflineMode();
|
||||||
// stop timers?
|
// 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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ class MessagingInterface {
|
|||||||
window.addEventListener("orientationchange", setVHvar);
|
window.addEventListener("orientationchange", setVHvar);
|
||||||
this.tagAppContainer.classList.add('touch-screen');
|
this.tagAppContainer.classList.add('touch-screen');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setWebsocket(socket) {
|
setWebsocket(socket) {
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ const VIDEO_SRC = {
|
|||||||
const VIDEO_OPTIONS = {
|
const VIDEO_OPTIONS = {
|
||||||
autoplay: false,
|
autoplay: false,
|
||||||
liveui: true, // try this
|
liveui: true, // try this
|
||||||
|
liveTracker: {
|
||||||
|
trackingThreshold: 0,
|
||||||
|
},
|
||||||
sources: [VIDEO_SRC],
|
sources: [VIDEO_SRC],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user