mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
* Support webfinger requests for the live account. Closes https://github.com/owncast/owncast/issues/1193
* Support for actor requests. Returns response for live actor. Closes https://github.com/owncast/owncast/issues/1203
* Handle follow and unfollow requests. Closes
https://github.com/owncast/owncast/issues/1191 and https://github.com/owncast/owncast/issues/1205 and https://github.com/owncast/owncast/issues/1206 and https://github.com/owncast/owncast/issues/1194
* Add basic support for sending out text activities. For https://github.com/owncast/owncast/issues/1192
* Some error handling and passing of dynamic local account names.
* Add hardcoded example image attachment to test post
* Centralize the map of accounts and inboxes
* No longer disable the preview generator based on YP toggle
* Send a federated message to followers when stream starts. For https://github.com/owncast/owncast/issues/1192
* Placeholder for attaching tags
* Add image description
* Save and get to outbox persistence. Return using outbox endpoint for actor
* Pass payloads to be handled through the gochan
* Handle undo follow requests explitly, not all undo requests
* Add API for manually sending simple federated messages. Closes #1215
* Verify inbox requests. Closes #1321
* Add route to fetch a single AP object by ID. For #1329
* Add responses to fediverse nodeinfo requests
* Set and get federation config values for admin
* Handle host-meta requests
* Do not send out message if disabled. Use saved go live message.
* Require AP-compatible content types for AP-related requests
* Rename ap models to apmodels for clarity
* Change how content type matching takes place.
* io -> ioutil
* Add stub delete activity callback
* Handle likes and announces to surface engagement in chat. Part of #1229
* Append url to go live posts
* Do not require specific content types for nodeinfo requests
* Add follow engagement chat message via AP
* add owncast user-agent to requests
* Set note visibility to public (for now)
* Fix saving/fetching a single object
* Add support for x-nodeinfo2 responses
* Point to the dev admin branch for ap
* Bundle in dev admin for testing
* Add error logging
* Add AP middleware back
* Point to the new external compatible logo endpoint
* Clean up more AP logging to help testing
* Tweak go live text and link hashtags
* Fix bug in fetching init time
* Send update actor activities when server details/profile is updated
* Add federation config overview to web client config
* Add additional actor properties
* Make the AP middleware checking more flexible when looking at types
* First pass at remote fediverse follow flow. For #1371
* Added a basic AP actor followers endpoint
* WIP client followers API
* Add profile-page reference to webfinger response
* Add aliases to webfinger response
* Fix content-type returned to be expected activitypub+json
* First pass at followers api
* Point at local dev copy of go-fed/activity
* Add custom toot Hashtag objects to posts
* Store additional user details to followers table
* Fix AP followers endpoint. Closes #1204
* Add owncast hashtag as an invisible tag to go live posts
* Reject AP requests when it is disabled
* Add actor util for generating full account user from person object
* Verify inbox requests before performing any other work
* Accept actor update requests
* Fix linter errors in federation branch
* Migrate AP SQL to sqlc for type safe queries
* Use the @unclearParadigm REST parameter helper
* Fix verifying post ID on AP engagement
* WIP privacy/request approval
* Style the remote follow modal
* First pass at a followers list component w/ mock data. #1370
* Revert "Use the @unclearParadigm REST parameter helper"
This reverts commit c8af8a413f.
* Fix get followers API
* Add support for requiring approval. Closes https://github.com/owncast/owncast/issues/1208
* Handle Applications as Actors partly for PeerTube support
* add temp todo list
* check route on load, this might change later
* style followers
* account for just 1 tab case
* Remove mock data. Allow showing follow button even when there are no external actions defined
* Point to actual followers API
* Support fallback img for follower views
* Remove duplicate verification. Add some additional verbose logging
* Bundle dev admin
* Add type to host-meta webfinger template response
* Tweak remote follow modal content
* WIP federation followers refactor
* Do not send pointer to middleware
* Update admin
* Add setting for toggling displaying fediverse engagement. Closes #1404
* Add in-development admin
* Do not enable cors on admin followers api
* Add db migration for updating messages table
* Enable empty string go live messages to disable
* Remove debug messages
* Rework some ActivityPub handling.
Create new Actor->Person handling.
Create new Actor->Service handling.
Add engagement handlers to send chat events and store event objects.
Store inbound activities to new ap_inbound_activities table.
* Support federated engagement events.
Store them in the messages table and surface them via chat events.
* Support federated event engatement in the chat
* Tweak web UI followers handling
* Point go.mod at remote fork instead of local
* Update admin
* Merged in develop. Couple fixes
* Update dev admin
* Update fedi engagement posts.
- Fix incorrect action text.
- Add action icons.
* Set public as to instead of cc for ap msg
* Updated styling for federated actions in chat
* Add support for blocking federated domains. Closes #1209
* Force checking of https in verify step
* Update dev admin
* Return user scopes in chat history api. Closes #1586
* Update dev admin
* Add AP outbound request worker pool. Closes #1571
* Disable (temporarily?) owncast tag on AP posts
* Consolidate creating activity+notes in outbound AP messages
* Add inbox worker pool. Closes #1570
* Update dev admin bundle
* Clean up some logs
* Re-enable inbound verfication
* Save full IRI to outbox instead of path
* Reject if full IRI is not found in outbox
* Use full ActivityPub user account in chat event
* Fix and expand follower APIs
- Add missing IDs to AP follower endpoints
- Split AP follower endpoints into initial request and pages.
- Support pagination in AP requests.
* Include IRI in error message
* Hide chat toggle when chat is hidden. Closes #1606
* Updates to followers pagination
* Set default go live message
* Remove log
* indirect -> direct import
* Updates for inbound federated event handling.
- Keep track of existing events and reject duplicates.
- Change what is sent to chat for surfing federated engagement.
- Keep track if outbound events are automated "go live" events or not.
* Update chat federated engagement.
* Update dev admin.
* Move from being a person to a bot (service). Closes #1619
* Only set server init date if not already set
* Only save notes to outbox able
* Rework private-mode followers/approvals
* API for returning a list of federated actions for #1573
* Fix too-small follower cells and jumpy tabs. Closes #1616 and closes #1516
* Fix shortcuts getting fired on inputs. Fixes #1489 and #1201
* Add spinner, autoclose + other fixes to follow modal. Fixes #1593
* Fix fetching a single object by IRI
* SendFederationMessage -> SendFederatedMessage
* Autolink and create tag objects from manual posts. Closes #1620
* Update dev admin bundle
* Handle engagement from non-automated/live posts
* Reject federated engagement actions if they do not match a local post
* Update dev admin bundle
* A bunch of cleanup
* Fix unused assignments and logic
* Remove unused function
* Add content warning and sentive content flag if stream is NSFW. Closes #1624
* Disable fetching objects by IRI when in private mode. Closes #1623
* Update the error message of the remote follow dialog. closes #1622
* Update dev admin
* Fix NREs throwing in test content
* Fix query that wasn't properly filtering out hidden messages
* Test against user being disabled instead of message visibility
* Fix automated test NRE
* Update comment
* Adjust federated engagement chat views. Closes #1617
* Add additional index to users table
* Add support for removing followers/requests. Closes #1630
* Reject federated actions from blocked actors. #1631
* Use fallback avatar if it fails to load. Closes #1635
* Fix styling of follower list. Closes #1636
* Add basic blurb stating they should follow the server. Closes #1641
* Update dev admin
* Set default go live message in migration. Closes #1642
* Reset the messages table on 0.0.11 schema migration
* Fix js error with moderation actions. Closes #1621
* Add a bit more clarification on follow modal. Closes #1599
* Remove todos
* Split out actor and domain blocking checks
* Check for errors on default values being set
* Clean up actor rejection due to being blocked
* Update dev admin
* Add colon to error to make it easier to read
* Remove markdown rendering of go live message. Reorganize text. Remove content warning. Closes #1645
* Break out the sort+render messages logic so it can be fired on visibility change. Closes #1643
* Do not send profile updates if federation is disabled
* Save follow references to inbound activities table
* Update dev admin
* Add blocked actor test
* Remove the overloaded term of Follow from social links
* Fix test running in memory only
* Remove "just" in engagement messags
* Replace star with heart for like action.
* Update dev admin
* Explicitly set cc as public
* Remove overly using the stream name in fediverse engagement messages
* Some federated/follow UI tweaks
* Remove explicit cc and bcc as they are not required
* Explicitly set the audience
* Remove extra margin
* Add Join Fediverse button to follow modal. Closes #1651
* Do not allow multiple follows to send multiple events. Closes #1650
* Give events a min height
* Do not allow old posts to be liked/shared. Closes #1652
* Remove value from log message
* Alert followers on private mode toggle
* Ignore clicks to follow button if disabled
* Remove underline from action buttons
* Add moderator icon to join message
* Update admin
* Post-merge remove unused var
* Remove pointing at feature branch
Co-authored-by: Ginger Wong <omqmail@gmail.com>
757 lines
21 KiB
Go
757 lines
21 KiB
Go
package data
|
|
|
|
import (
|
|
"errors"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/owncast/owncast/config"
|
|
"github.com/owncast/owncast/models"
|
|
"github.com/owncast/owncast/utils"
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
const (
|
|
extraContentKey = "extra_page_content"
|
|
streamTitleKey = "stream_title"
|
|
streamKeyKey = "stream_key"
|
|
logoPathKey = "logo_path"
|
|
serverSummaryKey = "server_summary"
|
|
serverWelcomeMessageKey = "server_welcome_message"
|
|
serverNameKey = "server_name"
|
|
serverURLKey = "server_url"
|
|
httpPortNumberKey = "http_port_number"
|
|
httpListenAddressKey = "http_listen_address"
|
|
rtmpPortNumberKey = "rtmp_port_number"
|
|
serverMetadataTagsKey = "server_metadata_tags"
|
|
directoryEnabledKey = "directory_enabled"
|
|
directoryRegistrationKeyKey = "directory_registration_key"
|
|
socialHandlesKey = "social_handles"
|
|
peakViewersSessionKey = "peak_viewers_session"
|
|
peakViewersOverallKey = "peak_viewers_overall"
|
|
lastDisconnectTimeKey = "last_disconnect_time"
|
|
ffmpegPathKey = "ffmpeg_path"
|
|
nsfwKey = "nsfw"
|
|
s3StorageEnabledKey = "s3_storage_enabled"
|
|
s3StorageConfigKey = "s3_storage_config"
|
|
videoLatencyLevel = "video_latency_level"
|
|
videoStreamOutputVariantsKey = "video_stream_output_variants"
|
|
chatDisabledKey = "chat_disabled"
|
|
externalActionsKey = "external_actions"
|
|
customStylesKey = "custom_styles"
|
|
videoCodecKey = "video_codec"
|
|
blockedUsernamesKey = "blocked_usernames"
|
|
publicKeyKey = "public_key"
|
|
privateKeyKey = "private_key"
|
|
serverInitDateKey = "server_init_date"
|
|
federationEnabledKey = "federation_enabled"
|
|
federationUsernameKey = "federation_username"
|
|
federationPrivateKey = "federation_private"
|
|
federationGoLiveMessageKey = "federation_go_live_message"
|
|
federationShowEngagementKey = "federation_show_engagement"
|
|
federationBlockedDomainsKey = "federation_blocked_domains"
|
|
suggestedUsernamesKey = "suggested_usernames"
|
|
)
|
|
|
|
// GetExtraPageBodyContent will return the user-supplied body content.
|
|
func GetExtraPageBodyContent() string {
|
|
content, err := _datastore.GetString(extraContentKey)
|
|
if err != nil {
|
|
log.Traceln(extraContentKey, err)
|
|
return config.GetDefaults().PageBodyContent
|
|
}
|
|
|
|
return content
|
|
}
|
|
|
|
// SetExtraPageBodyContent will set the user-supplied body content.
|
|
func SetExtraPageBodyContent(content string) error {
|
|
return _datastore.SetString(extraContentKey, content)
|
|
}
|
|
|
|
// GetStreamTitle will return the name of the current stream.
|
|
func GetStreamTitle() string {
|
|
title, err := _datastore.GetString(streamTitleKey)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
return title
|
|
}
|
|
|
|
// SetStreamTitle will set the name of the current stream.
|
|
func SetStreamTitle(title string) error {
|
|
return _datastore.SetString(streamTitleKey, title)
|
|
}
|
|
|
|
// GetStreamKey will return the inbound streaming password.
|
|
func GetStreamKey() string {
|
|
key, err := _datastore.GetString(streamKeyKey)
|
|
if err != nil {
|
|
log.Traceln(streamKeyKey, err)
|
|
return config.GetDefaults().StreamKey
|
|
}
|
|
|
|
return key
|
|
}
|
|
|
|
// SetStreamKey will set the inbound streaming password.
|
|
func SetStreamKey(key string) error {
|
|
return _datastore.SetString(streamKeyKey, key)
|
|
}
|
|
|
|
// GetLogoPath will return the path for the logo, relative to webroot.
|
|
func GetLogoPath() string {
|
|
logo, err := _datastore.GetString(logoPathKey)
|
|
if err != nil {
|
|
log.Traceln(logoPathKey, err)
|
|
return config.GetDefaults().Logo
|
|
}
|
|
|
|
if logo == "" {
|
|
return config.GetDefaults().Logo
|
|
}
|
|
|
|
return logo
|
|
}
|
|
|
|
// SetLogoPath will set the path for the logo, relative to webroot.
|
|
func SetLogoPath(logo string) error {
|
|
return _datastore.SetString(logoPathKey, logo)
|
|
}
|
|
|
|
// GetServerSummary will return the server summary text.
|
|
func GetServerSummary() string {
|
|
summary, err := _datastore.GetString(serverSummaryKey)
|
|
if err != nil {
|
|
log.Traceln(serverSummaryKey, err)
|
|
return ""
|
|
}
|
|
|
|
return summary
|
|
}
|
|
|
|
// SetServerSummary will set the server summary text.
|
|
func SetServerSummary(summary string) error {
|
|
return _datastore.SetString(serverSummaryKey, summary)
|
|
}
|
|
|
|
// GetServerWelcomeMessage will return the server welcome message text.
|
|
func GetServerWelcomeMessage() string {
|
|
welcomeMessage, err := _datastore.GetString(serverWelcomeMessageKey)
|
|
if err != nil {
|
|
log.Traceln(serverWelcomeMessageKey, err)
|
|
return config.GetDefaults().ServerWelcomeMessage
|
|
}
|
|
|
|
return welcomeMessage
|
|
}
|
|
|
|
// SetServerWelcomeMessage will set the server welcome message text.
|
|
func SetServerWelcomeMessage(welcomeMessage string) error {
|
|
return _datastore.SetString(serverWelcomeMessageKey, welcomeMessage)
|
|
}
|
|
|
|
// GetServerName will return the server name text.
|
|
func GetServerName() string {
|
|
name, err := _datastore.GetString(serverNameKey)
|
|
if err != nil {
|
|
log.Traceln(serverNameKey, err)
|
|
return config.GetDefaults().Name
|
|
}
|
|
|
|
return name
|
|
}
|
|
|
|
// SetServerName will set the server name text.
|
|
func SetServerName(name string) error {
|
|
return _datastore.SetString(serverNameKey, name)
|
|
}
|
|
|
|
// GetServerURL will return the server URL.
|
|
func GetServerURL() string {
|
|
url, err := _datastore.GetString(serverURLKey)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
return url
|
|
}
|
|
|
|
// SetServerURL will set the server URL.
|
|
func SetServerURL(url string) error {
|
|
return _datastore.SetString(serverURLKey, url)
|
|
}
|
|
|
|
// GetHTTPPortNumber will return the server HTTP port.
|
|
func GetHTTPPortNumber() int {
|
|
port, err := _datastore.GetNumber(httpPortNumberKey)
|
|
if err != nil {
|
|
log.Traceln(httpPortNumberKey, err)
|
|
return config.GetDefaults().WebServerPort
|
|
}
|
|
|
|
if port == 0 {
|
|
return config.GetDefaults().WebServerPort
|
|
}
|
|
return int(port)
|
|
}
|
|
|
|
// SetHTTPPortNumber will set the server HTTP port.
|
|
func SetHTTPPortNumber(port float64) error {
|
|
return _datastore.SetNumber(httpPortNumberKey, port)
|
|
}
|
|
|
|
// GetHTTPListenAddress will return the HTTP listen address.
|
|
func GetHTTPListenAddress() string {
|
|
address, err := _datastore.GetString(httpListenAddressKey)
|
|
if err != nil {
|
|
log.Traceln(httpListenAddressKey, err)
|
|
return config.GetDefaults().WebServerIP
|
|
}
|
|
return address
|
|
}
|
|
|
|
// SetHTTPListenAddress will set the server HTTP listen address.
|
|
func SetHTTPListenAddress(address string) error {
|
|
return _datastore.SetString(httpListenAddressKey, address)
|
|
}
|
|
|
|
// GetRTMPPortNumber will return the server RTMP port.
|
|
func GetRTMPPortNumber() int {
|
|
port, err := _datastore.GetNumber(rtmpPortNumberKey)
|
|
if err != nil {
|
|
log.Traceln(rtmpPortNumberKey, err)
|
|
return config.GetDefaults().RTMPServerPort
|
|
}
|
|
|
|
if port == 0 {
|
|
return config.GetDefaults().RTMPServerPort
|
|
}
|
|
|
|
return int(port)
|
|
}
|
|
|
|
// SetRTMPPortNumber will set the server RTMP port.
|
|
func SetRTMPPortNumber(port float64) error {
|
|
return _datastore.SetNumber(rtmpPortNumberKey, port)
|
|
}
|
|
|
|
// GetServerMetadataTags will return the metadata tags.
|
|
func GetServerMetadataTags() []string {
|
|
tagsString, err := _datastore.GetString(serverMetadataTagsKey)
|
|
if tagsString == "" {
|
|
return []string{}
|
|
}
|
|
|
|
if err != nil {
|
|
log.Traceln(serverMetadataTagsKey, err)
|
|
return []string{}
|
|
}
|
|
|
|
return strings.Split(tagsString, ",")
|
|
}
|
|
|
|
// SetServerMetadataTags will return the metadata tags.
|
|
func SetServerMetadataTags(tags []string) error {
|
|
tagString := strings.Join(tags, ",")
|
|
return _datastore.SetString(serverMetadataTagsKey, tagString)
|
|
}
|
|
|
|
// GetDirectoryEnabled will return if this server should register to YP.
|
|
func GetDirectoryEnabled() bool {
|
|
enabled, err := _datastore.GetBool(directoryEnabledKey)
|
|
if err != nil {
|
|
return config.GetDefaults().YPEnabled
|
|
}
|
|
|
|
return enabled
|
|
}
|
|
|
|
// SetDirectoryEnabled will set if this server should register to YP.
|
|
func SetDirectoryEnabled(enabled bool) error {
|
|
return _datastore.SetBool(directoryEnabledKey, enabled)
|
|
}
|
|
|
|
// SetDirectoryRegistrationKey will set the YP protocol registration key.
|
|
func SetDirectoryRegistrationKey(key string) error {
|
|
return _datastore.SetString(directoryRegistrationKeyKey, key)
|
|
}
|
|
|
|
// GetDirectoryRegistrationKey will return the YP protocol registration key.
|
|
func GetDirectoryRegistrationKey() string {
|
|
key, _ := _datastore.GetString(directoryRegistrationKeyKey)
|
|
return key
|
|
}
|
|
|
|
// GetSocialHandles will return the external social links.
|
|
func GetSocialHandles() []models.SocialHandle {
|
|
var socialHandles []models.SocialHandle
|
|
|
|
configEntry, err := _datastore.Get(socialHandlesKey)
|
|
if err != nil {
|
|
log.Traceln(socialHandlesKey, err)
|
|
return socialHandles
|
|
}
|
|
|
|
if err := configEntry.getObject(&socialHandles); err != nil {
|
|
log.Traceln(err)
|
|
return socialHandles
|
|
}
|
|
|
|
return socialHandles
|
|
}
|
|
|
|
// SetSocialHandles will set the external social links.
|
|
func SetSocialHandles(socialHandles []models.SocialHandle) error {
|
|
configEntry := ConfigEntry{Key: socialHandlesKey, Value: socialHandles}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// GetPeakSessionViewerCount will return the max number of viewers for this stream.
|
|
func GetPeakSessionViewerCount() int {
|
|
count, err := _datastore.GetNumber(peakViewersSessionKey)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return int(count)
|
|
}
|
|
|
|
// SetPeakSessionViewerCount will set the max number of viewers for this stream.
|
|
func SetPeakSessionViewerCount(count int) error {
|
|
return _datastore.SetNumber(peakViewersSessionKey, float64(count))
|
|
}
|
|
|
|
// GetPeakOverallViewerCount will return the overall max number of viewers.
|
|
func GetPeakOverallViewerCount() int {
|
|
count, err := _datastore.GetNumber(peakViewersOverallKey)
|
|
if err != nil {
|
|
return 0
|
|
}
|
|
return int(count)
|
|
}
|
|
|
|
// SetPeakOverallViewerCount will set the overall max number of viewers.
|
|
func SetPeakOverallViewerCount(count int) error {
|
|
return _datastore.SetNumber(peakViewersOverallKey, float64(count))
|
|
}
|
|
|
|
// GetLastDisconnectTime will return the time the last stream ended.
|
|
func GetLastDisconnectTime() (*utils.NullTime, error) {
|
|
var disconnectTime utils.NullTime
|
|
|
|
configEntry, err := _datastore.Get(lastDisconnectTimeKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := configEntry.getObject(&disconnectTime); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !disconnectTime.Valid || disconnectTime.Time.IsZero() {
|
|
return nil, err
|
|
}
|
|
|
|
return &disconnectTime, nil
|
|
}
|
|
|
|
// SetLastDisconnectTime will set the time the last stream ended.
|
|
func SetLastDisconnectTime(disconnectTime time.Time) error {
|
|
savedDisconnectTime := utils.NullTime{Time: disconnectTime, Valid: true}
|
|
configEntry := ConfigEntry{Key: lastDisconnectTimeKey, Value: savedDisconnectTime}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// SetNSFW will set if this stream has NSFW content.
|
|
func SetNSFW(isNSFW bool) error {
|
|
return _datastore.SetBool(nsfwKey, isNSFW)
|
|
}
|
|
|
|
// GetNSFW will return if this stream has NSFW content.
|
|
func GetNSFW() bool {
|
|
nsfw, err := _datastore.GetBool(nsfwKey)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return nsfw
|
|
}
|
|
|
|
// SetFfmpegPath will set the custom ffmpeg path.
|
|
func SetFfmpegPath(path string) error {
|
|
return _datastore.SetString(ffmpegPathKey, path)
|
|
}
|
|
|
|
// GetFfMpegPath will return the ffmpeg path.
|
|
func GetFfMpegPath() string {
|
|
path, err := _datastore.GetString(ffmpegPathKey)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return path
|
|
}
|
|
|
|
// GetS3Config will return the external storage configuration.
|
|
func GetS3Config() models.S3 {
|
|
configEntry, err := _datastore.Get(s3StorageConfigKey)
|
|
if err != nil {
|
|
return models.S3{Enabled: false}
|
|
}
|
|
|
|
var s3Config models.S3
|
|
if err := configEntry.getObject(&s3Config); err != nil {
|
|
return models.S3{Enabled: false}
|
|
}
|
|
|
|
return s3Config
|
|
}
|
|
|
|
// SetS3Config will set the external storage configuration.
|
|
func SetS3Config(config models.S3) error {
|
|
configEntry := ConfigEntry{Key: s3StorageConfigKey, Value: config}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// GetS3StorageEnabled will return if external storage is enabled.
|
|
func GetS3StorageEnabled() bool {
|
|
enabled, err := _datastore.GetBool(s3StorageEnabledKey)
|
|
if err != nil {
|
|
log.Traceln(err)
|
|
return false
|
|
}
|
|
|
|
return enabled
|
|
}
|
|
|
|
// SetS3StorageEnabled will enable or disable external storage.
|
|
func SetS3StorageEnabled(enabled bool) error {
|
|
return _datastore.SetBool(s3StorageEnabledKey, enabled)
|
|
}
|
|
|
|
// GetStreamLatencyLevel will return the stream latency level.
|
|
func GetStreamLatencyLevel() models.LatencyLevel {
|
|
level, err := _datastore.GetNumber(videoLatencyLevel)
|
|
if err != nil {
|
|
level = 2 // default
|
|
} else if level > 4 {
|
|
level = 4 // highest
|
|
}
|
|
|
|
return models.GetLatencyLevel(int(level))
|
|
}
|
|
|
|
// SetStreamLatencyLevel will set the stream latency level.
|
|
func SetStreamLatencyLevel(level float64) error {
|
|
return _datastore.SetNumber(videoLatencyLevel, level)
|
|
}
|
|
|
|
// GetStreamOutputVariants will return all of the stream output variants.
|
|
func GetStreamOutputVariants() []models.StreamOutputVariant {
|
|
configEntry, err := _datastore.Get(videoStreamOutputVariantsKey)
|
|
if err != nil {
|
|
return config.GetDefaults().StreamVariants
|
|
}
|
|
|
|
var streamOutputVariants []models.StreamOutputVariant
|
|
if err := configEntry.getObject(&streamOutputVariants); err != nil {
|
|
return config.GetDefaults().StreamVariants
|
|
}
|
|
|
|
if len(streamOutputVariants) == 0 {
|
|
return config.GetDefaults().StreamVariants
|
|
}
|
|
|
|
return streamOutputVariants
|
|
}
|
|
|
|
// SetStreamOutputVariants will set the stream output variants.
|
|
func SetStreamOutputVariants(variants []models.StreamOutputVariant) error {
|
|
configEntry := ConfigEntry{Key: videoStreamOutputVariantsKey, Value: variants}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// SetChatDisabled will disable chat if set to true.
|
|
func SetChatDisabled(disabled bool) error {
|
|
return _datastore.SetBool(chatDisabledKey, disabled)
|
|
}
|
|
|
|
// GetChatDisabled will return if chat is disabled.
|
|
func GetChatDisabled() bool {
|
|
disabled, err := _datastore.GetBool(chatDisabledKey)
|
|
if err == nil {
|
|
return disabled
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// GetExternalActions will return the registered external actions.
|
|
func GetExternalActions() []models.ExternalAction {
|
|
configEntry, err := _datastore.Get(externalActionsKey)
|
|
if err != nil {
|
|
return []models.ExternalAction{}
|
|
}
|
|
|
|
var externalActions []models.ExternalAction
|
|
if err := configEntry.getObject(&externalActions); err != nil {
|
|
return []models.ExternalAction{}
|
|
}
|
|
|
|
return externalActions
|
|
}
|
|
|
|
// SetExternalActions will save external actions.
|
|
func SetExternalActions(actions []models.ExternalAction) error {
|
|
configEntry := ConfigEntry{Key: externalActionsKey, Value: actions}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// SetCustomStyles will save a string with CSS to insert into the page.
|
|
func SetCustomStyles(styles string) error {
|
|
return _datastore.SetString(customStylesKey, styles)
|
|
}
|
|
|
|
// GetCustomStyles will return a string with CSS to insert into the page.
|
|
func GetCustomStyles() string {
|
|
style, err := _datastore.GetString(customStylesKey)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
return style
|
|
}
|
|
|
|
// SetVideoCodec will set the codec used for video encoding.
|
|
func SetVideoCodec(codec string) error {
|
|
return _datastore.SetString(videoCodecKey, codec)
|
|
}
|
|
|
|
// GetVideoCodec returns the codec to use for transcoding video.
|
|
func GetVideoCodec() string {
|
|
codec, err := _datastore.GetString(videoCodecKey)
|
|
if codec == "" || err != nil {
|
|
return "libx264" // Default value
|
|
}
|
|
|
|
return codec
|
|
}
|
|
|
|
// VerifySettings will perform a sanity check for specific settings values.
|
|
func VerifySettings() error {
|
|
if GetStreamKey() == "" {
|
|
return errors.New("no stream key set. Please set one in your config file")
|
|
}
|
|
|
|
logoPath := GetLogoPath()
|
|
if !utils.DoesFileExists(filepath.Join(config.DataDirectory, logoPath)) {
|
|
defaultLogo := filepath.Join(config.WebRoot, "img/logo.svg")
|
|
log.Traceln(logoPath, "not found in the data directory. copying a default logo.")
|
|
if err := utils.Copy(defaultLogo, filepath.Join(config.DataDirectory, "logo.svg")); err != nil {
|
|
log.Errorln("error copying default logo: ", err)
|
|
}
|
|
if err := SetLogoPath("logo.svg"); err != nil {
|
|
log.Errorln("unable to set default logo to logo.svg", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// FindHighestVideoQualityIndex will return the highest quality from a slice of variants.
|
|
func FindHighestVideoQualityIndex(qualities []models.StreamOutputVariant) int {
|
|
type IndexedQuality struct {
|
|
index int
|
|
quality models.StreamOutputVariant
|
|
}
|
|
|
|
if len(qualities) < 2 {
|
|
return 0
|
|
}
|
|
|
|
indexedQualities := make([]IndexedQuality, 0)
|
|
for index, quality := range qualities {
|
|
indexedQuality := IndexedQuality{index, quality}
|
|
indexedQualities = append(indexedQualities, indexedQuality)
|
|
}
|
|
|
|
sort.Slice(indexedQualities, func(a, b int) bool {
|
|
if indexedQualities[a].quality.IsVideoPassthrough && !indexedQualities[b].quality.IsVideoPassthrough {
|
|
return true
|
|
}
|
|
|
|
if !indexedQualities[a].quality.IsVideoPassthrough && indexedQualities[b].quality.IsVideoPassthrough {
|
|
return false
|
|
}
|
|
|
|
return indexedQualities[a].quality.VideoBitrate > indexedQualities[b].quality.VideoBitrate
|
|
})
|
|
|
|
return indexedQualities[0].index
|
|
}
|
|
|
|
// GetForbiddenUsernameList will return the blocked usernames as a comma separated string.
|
|
func GetForbiddenUsernameList() []string {
|
|
usernameString, err := _datastore.GetString(blockedUsernamesKey)
|
|
if err != nil {
|
|
return config.DefaultForbiddenUsernames
|
|
}
|
|
|
|
if usernameString == "" {
|
|
return config.DefaultForbiddenUsernames
|
|
}
|
|
|
|
blocklist := strings.Split(usernameString, ",")
|
|
|
|
return blocklist
|
|
}
|
|
|
|
// SetForbiddenUsernameList set the username blocklist as a comma separated string.
|
|
func SetForbiddenUsernameList(usernames []string) error {
|
|
usernameListString := strings.Join(usernames, ",")
|
|
return _datastore.SetString(blockedUsernamesKey, usernameListString)
|
|
}
|
|
|
|
// GetSuggestedUsernamesList will return the suggested usernames as a comma separated string.
|
|
// If the number of suggested usernames is smaller than 10, the number pool is not used (see code in the CreateAnonymousUser function).
|
|
func GetSuggestedUsernamesList() []string {
|
|
usernameString, err := _datastore.GetString(suggestedUsernamesKey)
|
|
|
|
if err != nil || usernameString == "" {
|
|
return []string{}
|
|
}
|
|
|
|
suggestionList := strings.Split(usernameString, ",")
|
|
|
|
return suggestionList
|
|
}
|
|
|
|
// SetSuggestedUsernamesList sets the username suggestion list as a comma separated string.
|
|
func SetSuggestedUsernamesList(usernames []string) error {
|
|
usernameListString := strings.Join(usernames, ",")
|
|
return _datastore.SetString(suggestedUsernamesKey, usernameListString)
|
|
}
|
|
|
|
// GetServerInitTime will return when the server was first setup.
|
|
func GetServerInitTime() (*utils.NullTime, error) {
|
|
var t utils.NullTime
|
|
|
|
configEntry, err := _datastore.Get(serverInitDateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := configEntry.getObject(&t); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if !t.Valid {
|
|
return nil, err
|
|
}
|
|
|
|
return &t, nil
|
|
}
|
|
|
|
// SetServerInitTime will set when the server was first created.
|
|
func SetServerInitTime(t time.Time) error {
|
|
nt := utils.NullTime{Time: t, Valid: true}
|
|
configEntry := ConfigEntry{Key: serverInitDateKey, Value: nt}
|
|
return _datastore.Save(configEntry)
|
|
}
|
|
|
|
// SetFederationEnabled will enable federation if set to true.
|
|
func SetFederationEnabled(enabled bool) error {
|
|
return _datastore.SetBool(federationEnabledKey, enabled)
|
|
}
|
|
|
|
// GetFederationEnabled will return if federation is enabled.
|
|
func GetFederationEnabled() bool {
|
|
enabled, err := _datastore.GetBool(federationEnabledKey)
|
|
if err == nil {
|
|
return enabled
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// SetFederationUsername will set the username used in federated activities.
|
|
func SetFederationUsername(username string) error {
|
|
return _datastore.SetString(federationUsernameKey, username)
|
|
}
|
|
|
|
// GetFederationUsername will return the username used in federated activities.
|
|
func GetFederationUsername() string {
|
|
username, err := _datastore.GetString(federationUsernameKey)
|
|
if username == "" || err != nil {
|
|
return config.GetDefaults().FederationUsername
|
|
}
|
|
|
|
return username
|
|
}
|
|
|
|
// SetFederationGoLiveMessage will set the message sent when going live.
|
|
func SetFederationGoLiveMessage(message string) error {
|
|
return _datastore.SetString(federationGoLiveMessageKey, message)
|
|
}
|
|
|
|
// GetFederationGoLiveMessage will return the message sent when going live.
|
|
func GetFederationGoLiveMessage() string {
|
|
// Empty message means it's disabled.
|
|
message, err := _datastore.GetString(federationGoLiveMessageKey)
|
|
if err != nil {
|
|
log.Traceln("unable to fetch go live message.", err)
|
|
}
|
|
|
|
return message
|
|
}
|
|
|
|
// SetFederationIsPrivate will set if federation activity is private.
|
|
func SetFederationIsPrivate(isPrivate bool) error {
|
|
return _datastore.SetBool(federationPrivateKey, isPrivate)
|
|
}
|
|
|
|
// GetFederationIsPrivate will return if federation is private.
|
|
func GetFederationIsPrivate() bool {
|
|
isPrivate, err := _datastore.GetBool(federationPrivateKey)
|
|
if err == nil {
|
|
return isPrivate
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// SetFederationShowEngagement will set if fediverse engagement shows in chat.
|
|
func SetFederationShowEngagement(showEngagement bool) error {
|
|
return _datastore.SetBool(federationShowEngagementKey, showEngagement)
|
|
}
|
|
|
|
// GetFederationShowEngagement will return if fediverse engagement shows in chat.
|
|
func GetFederationShowEngagement() bool {
|
|
showEngagement, err := _datastore.GetBool(federationShowEngagementKey)
|
|
if err == nil {
|
|
return showEngagement
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// SetBlockedFederatedDomains will set the blocked federated domains.
|
|
func SetBlockedFederatedDomains(domains []string) error {
|
|
return _datastore.SetString(federationBlockedDomainsKey, strings.Join(domains, ","))
|
|
}
|
|
|
|
// GetBlockedFederatedDomains will return a list of blocked federated domains.
|
|
func GetBlockedFederatedDomains() []string {
|
|
domains, err := _datastore.GetString(federationBlockedDomainsKey)
|
|
if err != nil {
|
|
return []string{}
|
|
}
|
|
|
|
if domains == "" {
|
|
return []string{}
|
|
}
|
|
|
|
return strings.Split(domains, ",")
|
|
}
|