0.0.6 -> Master (#731)
* Implement webhook events for external integrations (#574) * Implement webhook events for external integrations Reference #556 * move message type to models and remove duplicate * add json header so content type can be determined * Pass at migrating webhooks to datastore + management apis (#589) * Pass at migrating webhooks to datastore + management apis * Support nil lastUsed timestamps and return back the new webhook on create * Cleanup from review feedback * Simplify a bit Co-authored-by: Aaron Ogle <aaron@geekgonecrazy.com> Co-authored-by: Gabe Kangas <gabek@real-ity.com> * Webhook query cleanup * Access tokens + Send system message external API (#585) * New add, get and delete access token APIs * Create auth token middleware * Update last_used timestamp when using an access token * Add auth'ed endpoint for sending system messages * Cleanup * Update api spec for new apis * Commit updated API documentation * Add auth'ed endpoint for sending user chat messages * Return access token string * Commit updated API documentation * Fix route * Support nil lastUsed time * Commit updated Javascript packages * Remove duplicate function post rebase * Fix msg id generation * Update controllers/admin/chat.go Co-authored-by: Aaron Ogle <geekgonecrazy@users.noreply.github.com> * Webhook query cleanup * Add SystemMessageSent to EventType Co-authored-by: Owncast <owncast@owncast.online> Co-authored-by: Aaron Ogle <geekgonecrazy@users.noreply.github.com> * Set webhook as used on completion. Closes #610 * Display webhook errors as errors * Commit updated API documentation * Add user joined chat event * Change integration API paths. Update API spec * Update development version of admin that supports integration apis * Commit updated API documentation * Add automated tests for external integration APIs * check error * quiet this test for now * Route up some additional 3rd party apis. #638 * Commit updated API documentation * Save username on user joined event * Add missing scope to valid scopes list * Add generic chat action event API for 3rd parties. Closes #666 * Commit updated API documentation * First pass at moving WIP config framework into project for #234 * Only support exported fields in custom types * Using YP get/set key as a first pass at using the data layer. Fixes + integration. * Ignore test db * Start adding getters and setters for config values * More get/set config work. Starting to populate api with data * Wire up some config edit endpoints * More endpoints * Disable cors middleware * Add more endpoints and add test to test them * Remove the in-memory change APIs * Add endpoint for changing tags * Add more config endpoints * Starting to point more things away from config file and to the datastore * Populate YP with db data * Create new util method for parsing page body markdown and return it in api * Verify proposed path to ffmpeg * For development purposes show the config key in logs * Move stats values to datastore * Moving over more values to the datastore * Move S3 config to datastore * First pass the config -> db migrator * Add the start of the video config apis * It builds pointing everything away from the config * Tweak ffmpeg path error message * Backup database every hour. Closes #549 * Config + defaults + migration work for db * Cleanup logging * Remove all the old config structs * Add descriptive info about migration * Tweak ffmpeg validation logic * Fix db backup path. backup on db version migration * Set video and s3 configurations * Update api spec with new config endpoints * Add migrator for stats file * Commit updated API documentation * Use a dynamic system port for internal HLS writes. Closes #577 (#626) * Use a dynamic system port for internal HLS writes. Closes #577 * Cleanup * YP key migration to datastore * Create a backup directory if needed before migrations * Remove config test that no longer makes sense. Cleanup. * Change number types from float32 to float64 * Update automated test suite * Allow restoring a database backup via command line flags. Closes #549 * Add new hls segment config api * Commit updated API documentation * Update apis to require a value container property * add socialHandles api * Commit updated API documentation * Add new latancy level setting to replace segment settings * Commit updated API documentation * Fix spelling * Commit updated API documentation * hardcode a json api of available social platforms * Add additional icons * Return social handles in server config api * Add socialhandles validation to test * Move list of hard coded social platforms to an api * Remove audio only code from transcoder since we do not use it * Add latency levels api + snapshot of video settings as current broadcast * Add config/serverurl endpoint * Return 404 on YP api if disabled * Surface stream title in YP response * Add stream title to web ui * Cleanup log message. Closes #520 * Rename ffmpeg package to transcoder * Add ws package for testing * Reduce chat backlog to past 5hrs, max 50. Closes #548 * Fix error formatting * Add endpoint for resetting yp registration * Add yp/reset to api spec. return status in response * Return zero viewer count if stream is offline. Closes #422 * Post-rebase fixes * Fix merge conflict in openapi file * Commit updated API documentation * Standardize controller names * Support setting the stream key via the command line. Closes #665 * Return social handles with YP data. First half of https://github.com/owncast/owncast-yp/issues/28 * Give the YP package access to server status regardless if enabled or not * Change delay in automated tests * Add stream title integration API. For #638 * Commit updated API documentation * Add storage to the migrator * Missing returning NSFW value in server config * Add flag to ignore websocket client. Closes #537 * Add error for parsing broadcaster metadata * Add support for a cli specified http server port. Closes #674 * Add cpu usage levels and a temporary mapping between it and libx264 presets * Test for valid url endpoint when saving s3 config * Re-configure storage on every stream to allow changing storage providers * After 5 minutes of a stream being stopped clear the stream title * Hide viewer count once stream goes offline instead of when player stops * Pull steamTitle from the status that gets updated instead of the config * Commit updated API documentation * Optionally show stream title in the header * Reset stream title when server starts * Show chat action when stream title is updated * Allow system messages to come back in persistence * Split out getting chat history for moderation + fix tests * Remove server title and standardize on name only * Commit updated API documentation * Bump github.com/aws/aws-sdk-go from 1.37.1 to 1.37.2 (#680) Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.37.1 to 1.37.2. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.37.1...v1.37.2) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add video variant and stream latency config file migrator * Remove mostly unused disable upgrade check bool * Commit updated API documentation * Allow bundling the admin from the 0.0.6 branch * Fix saving port numbers * Use name instead of old title on window focus * Work on latency levels. Fix test to use levels. Clean up transcoder to only reference levels * Another place where title -> name * Fix test * Bump github.com/aws/aws-sdk-go from 1.37.2 to 1.37.3 (#690) Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.37.2 to 1.37.3. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.37.2...v1.37.3) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update dependabot config * Bump github.com/aws/aws-sdk-go from 1.37.3 to 1.37.5 (#693) Bumps [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) from 1.37.3 to 1.37.5. - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Changelog](https://github.com/aws/aws-sdk-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.37.3...v1.37.5) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump video.js from 7.10.2 to 7.11.4 in /build/javascript (#694) * Bump video.js from 7.10.2 to 7.11.4 in /build/javascript Bumps [video.js](https://github.com/videojs/video.js) from 7.10.2 to 7.11.4. - [Release notes](https://github.com/videojs/video.js/releases) - [Changelog](https://github.com/videojs/video.js/blob/main/CHANGELOG.md) - [Commits](https://github.com/videojs/video.js/compare/v7.10.2...v7.11.4) Signed-off-by: dependabot[bot] <support@github.com> * Commit updated Javascript packages Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Owncast <owncast@owncast.online> * Make the latency migrator dynamic so I can tweak values easier * Split out fetching ffmpeg path from validating the path so it can be changed in the admin * Some commenting and linter cleanup * Validate the path for a logo change and throw an error if it does not exist * Logo change requests have to be a real file now * Cleanup, making linter happy * Format javascript on push * Only format js in master * Tweak latency level values * Remove unused config file examples * Fix thumbnail generation after messing with the ffmpeg path getter * Reduce how often we report high hardware utilization warnings * Bundle the 0.0.6 branch version of the admin * Return validated ffmpeg path in admin server config * Change the logo to be stored in the data directory instead of webroot * Bump postcss from 8.2.4 to 8.2.5 in /build/javascript (#702) Bumps [postcss](https://github.com/postcss/postcss) from 8.2.4 to 8.2.5. - [Release notes](https://github.com/postcss/postcss/releases) - [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md) - [Commits](https://github.com/postcss/postcss/compare/8.2.4...8.2.5) Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Default config file no longer used * don't show stream title when offline addresses https://github.com/owncast/owncast/issues/677 * Remove auto-clearing stream title. #677 * webroot -> data when using logo as thumbnail * Do not list websocket/access token create/delete as integration APIs * Commit updated API documentation * Bundle updated admin * Remove pointing to the 0.0.6 admin branch * Linter cleanup * Linter cleanup * Add donations and follow links to show up under social handles * Prettified Code! * More linter cleanup * Update admin bundle * Remove use of platforms.js and return icons with social handles. Closes #732 * Update admin bundle * Support custom config path for use in migration * Remove unused platform-logos.gif * Reduce log level of message * Remove unused logo files in static dir * Handle dev vs. release build info * Restore logo.png for initial thumbnail * Cleanup some files from the build process that are not needed * Fix incorrect build-time injection var * Fix missing file getting copied to the build * Remove console directory message. * Update admin bundle * Fix comment * Report storage setup error * add some value set error checking * Use validated dynamic ffmpeg path for animated gif preview * Make chat message links be white so they don't hide in the bg. Closes #599 * Restore conditional that was accidentally removed Co-authored-by: Aaron Ogle <geekgonecrazy@users.noreply.github.com> Co-authored-by: Owncast <owncast@owncast.online> Co-authored-by: Ginger Wong <omqmail@gmail.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: nebunez <uoj2y7wak869@opayq.net> Co-authored-by: gabek <gabek@users.noreply.github.com>
This commit is contained in:
53
models/accessToken.go
Normal file
53
models/accessToken.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// ScopeCanSendUserMessages will allow sending chat messages as users.
|
||||
ScopeCanSendUserMessages = "CAN_SEND_MESSAGES"
|
||||
// ScopeCanSendSystemMessages will allow sending chat messages as the system.
|
||||
ScopeCanSendSystemMessages = "CAN_SEND_SYSTEM_MESSAGES"
|
||||
// ScopeHasAdminAccess will allow performing administrative actions on the server.
|
||||
ScopeHasAdminAccess = "HAS_ADMIN_ACCESS"
|
||||
)
|
||||
|
||||
// For a scope to be seen as "valid" it must live in this slice.
|
||||
var validAccessTokenScopes = []string{
|
||||
ScopeCanSendUserMessages,
|
||||
ScopeCanSendSystemMessages,
|
||||
ScopeHasAdminAccess,
|
||||
}
|
||||
|
||||
// AccessToken gives access to 3rd party code to access specific Owncast APIs.
|
||||
type AccessToken struct {
|
||||
Token string `json:"token"`
|
||||
Name string `json:"name"`
|
||||
Scopes []string `json:"scopes"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
LastUsed *time.Time `json:"lastUsed"`
|
||||
}
|
||||
|
||||
// HasValidScopes will verify that all the scopes provided are valid.
|
||||
// This is not a efficient method.
|
||||
func HasValidScopes(scopes []string) bool {
|
||||
for _, scope := range scopes {
|
||||
if !findItemInSlice(validAccessTokenScopes, scope) {
|
||||
log.Errorln("Invalid scope", scope)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findItemInSlice(slice []string, value string) bool {
|
||||
for _, item := range slice {
|
||||
if item == value {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -9,6 +9,7 @@ type Broadcaster struct {
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
// InboundStreamDetails represents an inbound broadcast stream.
|
||||
type InboundStreamDetails struct {
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
|
||||
12
models/chatActionEvent.go
Normal file
12
models/chatActionEvent.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// ChatActionEvent represents a generic action that took place by a chat user.
|
||||
type ChatActionEvent struct {
|
||||
Username string `json:"username"`
|
||||
Type EventType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/microcosm-cc/bluemonday"
|
||||
"github.com/teris-io/shortid"
|
||||
"github.com/yuin/goldmark"
|
||||
"github.com/yuin/goldmark/extension"
|
||||
"github.com/yuin/goldmark/renderer/html"
|
||||
@@ -18,8 +19,9 @@ type ChatEvent struct {
|
||||
|
||||
Author string `json:"author,omitempty"`
|
||||
Body string `json:"body,omitempty"`
|
||||
RawBody string `json:"-"`
|
||||
ID string `json:"id"`
|
||||
MessageType string `json:"type"`
|
||||
MessageType EventType `json:"type"`
|
||||
Visible bool `json:"visible"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
}
|
||||
@@ -29,15 +31,24 @@ func (m ChatEvent) Valid() bool {
|
||||
return m.Author != "" && m.Body != "" && m.ID != ""
|
||||
}
|
||||
|
||||
// SetDefaults will set default values on a chat event object.
|
||||
func (m *ChatEvent) SetDefaults() {
|
||||
id, _ := shortid.Generate()
|
||||
m.ID = id
|
||||
m.Timestamp = time.Now()
|
||||
m.Visible = true
|
||||
}
|
||||
|
||||
// RenderAndSanitizeMessageBody will turn markdown into HTML, sanitize raw user-supplied HTML and standardize
|
||||
// the message into something safe and renderable for clients.
|
||||
func (m *ChatEvent) RenderAndSanitizeMessageBody() {
|
||||
raw := m.Body
|
||||
m.RawBody = m.Body
|
||||
|
||||
// Set the new, sanitized and rendered message body
|
||||
m.Body = RenderAndSanitize(raw)
|
||||
m.Body = RenderAndSanitize(m.RawBody)
|
||||
}
|
||||
|
||||
// Empty will return if this message's contents is empty.
|
||||
func (m *ChatEvent) Empty() bool {
|
||||
return m.Body == ""
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ import (
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
// ConnectedClientsResponse is the response of the currently connected chat clients.
|
||||
type ConnectedClientsResponse struct {
|
||||
Clients []Client `json:"clients"`
|
||||
}
|
||||
|
||||
// Client represents a single chat client.
|
||||
type Client struct {
|
||||
ConnectedAt time.Time `json:"connectedAt"`
|
||||
LastSeen time.Time `json:"-"`
|
||||
@@ -23,6 +25,7 @@ type Client struct {
|
||||
Geo *geoip.GeoDetails `json:"geo"`
|
||||
}
|
||||
|
||||
// GenerateClientFromRequest will return a chat client from a http request.
|
||||
func GenerateClientFromRequest(req *http.Request) Client {
|
||||
return Client{
|
||||
ConnectedAt: time.Now(),
|
||||
|
||||
7
models/currentBroadcast.go
Normal file
7
models/currentBroadcast.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package models
|
||||
|
||||
// CurrentBroadcast represents the configuration associated with the currently active stream.
|
||||
type CurrentBroadcast struct {
|
||||
OutputSettings []StreamOutputVariant `json:"outputSettings"`
|
||||
LatencyLevel LatencyLevel `json:"latencyLevel"`
|
||||
}
|
||||
27
models/eventType.go
Normal file
27
models/eventType.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package models
|
||||
|
||||
// EventType is the type of a websocket event.
|
||||
type EventType = string
|
||||
|
||||
const (
|
||||
// MessageSent is the event sent when a chat event takes place.
|
||||
MessageSent EventType = "CHAT"
|
||||
// UserJoined is the event sent when a chat user join action takes place.
|
||||
UserJoined EventType = "USER_JOINED"
|
||||
// UserNameChanged is the event sent when a chat username change takes place.
|
||||
UserNameChanged EventType = "NAME_CHANGE"
|
||||
// VisibiltyToggled is the event sent when a chat message's visibility changes.
|
||||
VisibiltyToggled EventType = "VISIBILITY-UPDATE"
|
||||
// PING is a ping message.
|
||||
PING EventType = "PING"
|
||||
// PONG is a pong message.
|
||||
PONG EventType = "PONG"
|
||||
// StreamStarted represents a stream started event.
|
||||
StreamStarted EventType = "STREAM_STARTED"
|
||||
// StreamStopped represents a stream stopped event.
|
||||
StreamStopped EventType = "STREAM_STOPPED"
|
||||
// SystemMessageSent is the event sent when a system message is sent.
|
||||
SystemMessageSent EventType = "SYSTEM"
|
||||
// ChatActionSent is a generic chat action that can be used for anything that doesn't need specific handling or formatting.
|
||||
ChatActionSent EventType = "CHAT_ACTION"
|
||||
)
|
||||
25
models/latencyLevels.go
Normal file
25
models/latencyLevels.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package models
|
||||
|
||||
// LatencyLevel is a representation of HLS configuration values.
|
||||
type LatencyLevel struct {
|
||||
Level int `json:"level"`
|
||||
SecondsPerSegment int `json:"-"`
|
||||
SegmentCount int `json:"-"`
|
||||
}
|
||||
|
||||
// GetLatencyConfigs will return the available latency level options.
|
||||
func GetLatencyConfigs() map[int]LatencyLevel {
|
||||
return map[int]LatencyLevel{
|
||||
1: {Level: 1, SecondsPerSegment: 1, SegmentCount: 2},
|
||||
2: {Level: 2, SecondsPerSegment: 2, SegmentCount: 2},
|
||||
3: {Level: 3, SecondsPerSegment: 3, SegmentCount: 3},
|
||||
4: {Level: 4, SecondsPerSegment: 3, SegmentCount: 4}, // Default
|
||||
5: {Level: 5, SecondsPerSegment: 4, SegmentCount: 5},
|
||||
6: {Level: 6, SecondsPerSegment: 6, SegmentCount: 10},
|
||||
}
|
||||
}
|
||||
|
||||
// GetLatencyLevel will return the latency level at index.
|
||||
func GetLatencyLevel(index int) LatencyLevel {
|
||||
return GetLatencyConfigs()[index]
|
||||
}
|
||||
@@ -2,9 +2,9 @@ package models
|
||||
|
||||
// NameChangeEvent represents a user changing their name in chat.
|
||||
type NameChangeEvent struct {
|
||||
OldName string `json:"oldName"`
|
||||
NewName string `json:"newName"`
|
||||
Image string `json:"image"`
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id"`
|
||||
OldName string `json:"oldName"`
|
||||
NewName string `json:"newName"`
|
||||
Image string `json:"image"`
|
||||
Type EventType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ package models
|
||||
|
||||
// PingMessage represents a ping message between the client and server.
|
||||
type PingMessage struct {
|
||||
MessageType string `json:"type"`
|
||||
MessageType EventType `json:"type"`
|
||||
}
|
||||
|
||||
13
models/s3Storage.go
Normal file
13
models/s3Storage.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
// S3 is the storage configuration.
|
||||
type S3 struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Endpoint string `json:"endpoint,omitempty"`
|
||||
ServingEndpoint string `json:"servingEndpoint,omitempty"`
|
||||
AccessKey string `json:"accessKey,omitempty"`
|
||||
Secret string `json:"secret,omitempty"`
|
||||
Bucket string `json:"bucket,omitempty"`
|
||||
Region string `json:"region,omitempty"`
|
||||
ACL string `json:"acl,omitempty"`
|
||||
}
|
||||
110
models/socialHandle.go
Normal file
110
models/socialHandle.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package models
|
||||
|
||||
// SocialHandle represents an external link.
|
||||
type SocialHandle struct {
|
||||
Platform string `yaml:"platform" json:"platform,omitempty"`
|
||||
URL string `yaml:"url" json:"url,omitempty"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
// GetSocialHandle will return the details for a supported platform.
|
||||
func GetSocialHandle(platform string) *SocialHandle {
|
||||
allPlatforms := GetAllSocialHandles()
|
||||
if platform, ok := allPlatforms[platform]; ok {
|
||||
return &platform
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetAllSocialHandles will return a list of all the social platforms we support.
|
||||
func GetAllSocialHandles() map[string]SocialHandle {
|
||||
socialHandlePlatforms := map[string]SocialHandle{
|
||||
"bandcamp": {
|
||||
Platform: "Bandcamp",
|
||||
Icon: "/img/platformlogos/bandcamp.svg",
|
||||
},
|
||||
"discord": {
|
||||
Platform: "Discord",
|
||||
Icon: "/img/platformlogos/discord.svg",
|
||||
},
|
||||
"facebook": {
|
||||
Platform: "Facebook",
|
||||
Icon: "/img/platformlogos/facebook.svg",
|
||||
},
|
||||
"github": {
|
||||
Platform: "GitHub",
|
||||
Icon: "/img/platformlogos/github.svg",
|
||||
},
|
||||
"gitlab": {
|
||||
Platform: "GitLab",
|
||||
Icon: "/img/platformlogos/gitlab.svg",
|
||||
},
|
||||
"instagram": {
|
||||
Platform: "Instagram",
|
||||
Icon: "/img/platformlogos/instagram.svg",
|
||||
},
|
||||
"keyoxide": {
|
||||
Platform: "Keyoxide",
|
||||
Icon: "/img/platformlogos/keyoxide.png",
|
||||
},
|
||||
"kofi": {
|
||||
Platform: "Ko-Fi",
|
||||
Icon: "/img/platformlogos/ko-fi.svg",
|
||||
},
|
||||
"linkedin": {
|
||||
Platform: "LinkedIn",
|
||||
Icon: "/img/platformlogos/linkedin.svg",
|
||||
},
|
||||
"mastodon": {
|
||||
Platform: "Mastodon",
|
||||
Icon: "/img/platformlogos/mastodon.svg",
|
||||
},
|
||||
"patreon": {
|
||||
Platform: "Patreon",
|
||||
Icon: "/img/platformlogos/patreon.svg",
|
||||
},
|
||||
"paypal": {
|
||||
Platform: "Paypal",
|
||||
Icon: "/img/platformlogos/paypal.svg",
|
||||
},
|
||||
"snapchat": {
|
||||
Platform: "Snapchat",
|
||||
Icon: "/img/platformlogos/snapchat.svg",
|
||||
},
|
||||
"soundcloud": {
|
||||
Platform: "Soundcloud",
|
||||
Icon: "/img/platformlogos/soundcloud.svg",
|
||||
},
|
||||
"spotify": {
|
||||
Platform: "Spotify",
|
||||
Icon: "/img/platformlogos/spotify.svg",
|
||||
},
|
||||
"tiktok": {
|
||||
Platform: "TikTok",
|
||||
Icon: "/img/platformlogos/tiktok.svg",
|
||||
},
|
||||
"twitch": {
|
||||
Platform: "Twitch",
|
||||
Icon: "/img/platformlogos/twitch.svg",
|
||||
},
|
||||
"twitter": {
|
||||
Platform: "Twitter",
|
||||
Icon: "/img/platformlogos/twitter.svg",
|
||||
},
|
||||
"youtube": {
|
||||
Platform: "YouTube",
|
||||
Icon: "/img/platformlogos/youtube.svg",
|
||||
},
|
||||
"donate": {
|
||||
Platform: "Donations",
|
||||
Icon: "/img/platformlogos/donate.svg",
|
||||
},
|
||||
"follow": {
|
||||
Platform: "Follow",
|
||||
Icon: "/img/platformlogos/follow.svg",
|
||||
},
|
||||
}
|
||||
|
||||
return socialHandlePlatforms
|
||||
}
|
||||
@@ -13,4 +13,5 @@ type Status struct {
|
||||
LastDisconnectTime utils.NullTime `json:"lastDisconnectTime"`
|
||||
|
||||
VersionNumber string `json:"versionNumber"`
|
||||
StreamTitle string `json:"streamTitle"`
|
||||
}
|
||||
|
||||
89
models/streamOutputVariant.go
Normal file
89
models/streamOutputVariant.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package models
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// StreamOutputVariant defines the output specifics of a single HLS stream variant.
|
||||
type StreamOutputVariant struct {
|
||||
// Enable passthrough to copy the video and/or audio directly from the
|
||||
// incoming stream and disable any transcoding. It will ignore any of
|
||||
// the below settings.
|
||||
IsVideoPassthrough bool `yaml:"videoPassthrough" json:"videoPassthrough"`
|
||||
IsAudioPassthrough bool `yaml:"audioPassthrough" json:"audioPassthrough"`
|
||||
|
||||
VideoBitrate int `yaml:"videoBitrate" json:"videoBitrate"`
|
||||
AudioBitrate int `yaml:"audioBitrate" json:"audioBitrate"`
|
||||
|
||||
// Set only one of these in order to keep your current aspect ratio.
|
||||
// Or set neither to not scale the video.
|
||||
ScaledWidth int `yaml:"scaledWidth" json:"scaledWidth,omitempty"`
|
||||
ScaledHeight int `yaml:"scaledHeight" json:"scaledHeight,omitempty"`
|
||||
|
||||
Framerate int `yaml:"framerate" json:"framerate"`
|
||||
EncoderPreset string `yaml:"encoderPreset" json:"encoderPreset"` // Remove after migration is no longer used
|
||||
// CPUUsageLevel represents a codec preset to configure CPU usage.
|
||||
CPUUsageLevel int `json:"cpuUsageLevel"`
|
||||
}
|
||||
|
||||
// GetFramerate returns the framerate or default.
|
||||
func (q *StreamOutputVariant) GetFramerate() int {
|
||||
if q.IsVideoPassthrough {
|
||||
return 0
|
||||
}
|
||||
|
||||
if q.Framerate > 0 {
|
||||
return q.Framerate
|
||||
}
|
||||
|
||||
return 24
|
||||
}
|
||||
|
||||
// GetEncoderPreset returns the preset or default.
|
||||
func (q *StreamOutputVariant) GetEncoderPreset() string {
|
||||
if q.IsVideoPassthrough {
|
||||
return ""
|
||||
}
|
||||
|
||||
if q.EncoderPreset != "" {
|
||||
return q.EncoderPreset
|
||||
}
|
||||
|
||||
return "veryfast"
|
||||
}
|
||||
|
||||
// GetCPUUsageLevel will return the libx264 codec encoder preset that maps to a level.
|
||||
func (q *StreamOutputVariant) GetCPUUsageLevel() int {
|
||||
presetMapping := map[string]int{
|
||||
"ultrafast": 1,
|
||||
"superfast": 2,
|
||||
"veryfast": 3,
|
||||
"faster": 4,
|
||||
"fast": 5,
|
||||
}
|
||||
|
||||
return presetMapping[q.GetEncoderPreset()]
|
||||
}
|
||||
|
||||
// GetIsAudioPassthrough will return if this variant audio is passthrough.
|
||||
func (q *StreamOutputVariant) GetIsAudioPassthrough() bool {
|
||||
if q.IsAudioPassthrough {
|
||||
return true
|
||||
}
|
||||
|
||||
if q.AudioBitrate == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalJSON is a custom JSON marshal function for video stream qualities.
|
||||
func (q *StreamOutputVariant) MarshalJSON() ([]byte, error) {
|
||||
type Alias StreamOutputVariant
|
||||
return json.Marshal(&struct {
|
||||
Framerate int `json:"framerate"`
|
||||
*Alias
|
||||
}{
|
||||
Framerate: q.GetFramerate(),
|
||||
Alias: (*Alias)(q),
|
||||
})
|
||||
}
|
||||
11
models/userJoinedEvent.go
Normal file
11
models/userJoinedEvent.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// UserJoinedEvent represents an event when a user joins the chat.
|
||||
type UserJoinedEvent struct {
|
||||
Username string `json:"username"`
|
||||
Type EventType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
}
|
||||
33
models/webhook.go
Normal file
33
models/webhook.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
// Webhook is an event that is sent to 3rd party, external services with details about something that took place within an Owncast server.
|
||||
type Webhook struct {
|
||||
ID int `json:"id"`
|
||||
URL string `json:"url"`
|
||||
Events []EventType `json:"events"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
LastUsed *time.Time `json:"lastUsed"`
|
||||
}
|
||||
|
||||
// For an event to be seen as "valid" it must live in this slice.
|
||||
var validEvents = []EventType{
|
||||
MessageSent,
|
||||
UserJoined,
|
||||
UserNameChanged,
|
||||
VisibiltyToggled,
|
||||
StreamStarted,
|
||||
StreamStopped,
|
||||
}
|
||||
|
||||
// HasValidEvents will verify that all the events provided are valid.
|
||||
// This is not a efficient method.
|
||||
func HasValidEvents(events []EventType) bool {
|
||||
for _, event := range events {
|
||||
if !findItemInSlice(validEvents, event) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user