Compare commits
135 Commits
fe040070de
...
2c2bf2b5bb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c2bf2b5bb | ||
|
|
32bf67b026 | ||
|
|
d578f01348 | ||
|
|
8985947d7f | ||
|
|
e1acfee49d | ||
|
|
49c07594fb | ||
|
|
dc48e0bca7 | ||
|
|
0b5d7c8a4d | ||
|
|
56d52c283c | ||
|
|
8fa2546bef | ||
|
|
70bbcb97b8 | ||
|
|
d8abe74e5a | ||
|
|
681111ceb2 | ||
|
|
284833d6a0 | ||
|
|
a566b9c9f1 | ||
|
|
621aebdd3c | ||
|
|
2be188a82f | ||
|
|
e17b443726 | ||
|
|
dfc934ce84 | ||
|
|
512e4dc575 | ||
|
|
421cdd0693 | ||
|
|
df06d9ad97 | ||
|
|
7f42981ba7 | ||
|
|
f3029ca782 | ||
|
|
58657804cb | ||
|
|
d21b10f118 | ||
|
|
ae48128441 | ||
|
|
b278027b88 | ||
|
|
f45a5b16fa | ||
|
|
f3d660853c | ||
|
|
aecf7aa9bb | ||
|
|
37c18ec8ab | ||
|
|
4c7ccdbbf9 | ||
|
|
a20a9931f7 | ||
|
|
b177333ec6 | ||
|
|
5042c7ced2 | ||
|
|
71c88c94a3 | ||
|
|
41a6449836 | ||
|
|
b656f88417 | ||
|
|
ee5dc3b7c8 | ||
|
|
1476405609 | ||
|
|
7830b3765a | ||
|
|
f9f61876df | ||
|
|
17d433749c | ||
|
|
9989653d00 | ||
|
|
6399df7f9e | ||
|
|
99acc19cee | ||
|
|
eca880ac1f | ||
|
|
f215809f1d | ||
|
|
77d2bacbad | ||
|
|
1b1144c6df | ||
|
|
971e3ea092 | ||
|
|
24e2552e4c | ||
|
|
56f6aa8add | ||
|
|
de8579bcd6 | ||
|
|
56ede52346 | ||
|
|
8269ae3209 | ||
|
|
674c9168ec | ||
|
|
801e91d2f1 | ||
|
|
1e1dc0ff49 | ||
|
|
fb75f1bd95 | ||
|
|
af56597341 | ||
|
|
214c202552 | ||
|
|
ad64956027 | ||
|
|
13d2ad9079 | ||
|
|
83ef466ee1 | ||
|
|
a8026c13bc | ||
|
|
d31d2948c3 | ||
|
|
4d68c7b561 | ||
|
|
25cd9b6d53 | ||
|
|
ecba3cc003 | ||
|
|
89dc1776d7 | ||
|
|
97fcdfd914 | ||
|
|
0af864ea8f | ||
|
|
121cd37c8c | ||
|
|
06c09f12de | ||
|
|
d1117494b0 | ||
|
|
68a903b83a | ||
|
|
c8c91506cd | ||
|
|
a1a497f5c1 | ||
|
|
219f76d891 | ||
|
|
ad9b01f442 | ||
|
|
962d03710d | ||
|
|
2ebc64b3b1 | ||
|
|
5ca7249388 | ||
|
|
50a4224224 | ||
|
|
ac009f574e | ||
|
|
b9d8fbffe2 | ||
|
|
40b97e6bc1 | ||
|
|
134093b9d2 | ||
|
|
d123a2c020 | ||
|
|
fbd501f57e | ||
|
|
ed7bd001ee | ||
|
|
83b3a0da5e | ||
|
|
e04e079243 | ||
|
|
d4fd75b9c7 | ||
|
|
6fbb3b9565 | ||
|
|
42005608fa | ||
|
|
538ebaf7bb | ||
|
|
2be0aebd6d | ||
|
|
fdaf25d92e | ||
|
|
5fc4e56bf9 | ||
|
|
392e437b9a | ||
|
|
3066d6b82e | ||
|
|
2f941be5c0 | ||
|
|
ff058ca777 | ||
|
|
3f321d3a1c | ||
|
|
490c38bd31 | ||
|
|
019cdb169c | ||
|
|
9d0c7c1edb | ||
|
|
88a96f0eae | ||
|
|
b7d8a5ea99 | ||
|
|
5d8c6348bc | ||
|
|
a934b89a53 | ||
|
|
9ccf19eb64 | ||
|
|
de3eac2b2f | ||
|
|
76abc0bbfb | ||
|
|
3bb2ba18e5 | ||
|
|
e71144a68d | ||
|
|
7a367a933b | ||
|
|
c1cb96fa57 | ||
|
|
28c6947a43 | ||
|
|
00b9dec218 | ||
|
|
8e89dfb345 | ||
|
|
ed21911288 | ||
|
|
d9aeb32852 | ||
|
|
3262d3b875 | ||
|
|
af88ee386b | ||
|
|
50f39284ce | ||
|
|
9c36e196b7 | ||
|
|
274c85ac2b | ||
|
|
5eaa06cf15 | ||
|
|
86c20e0a39 | ||
|
|
90a8ebbfa4 | ||
|
|
e995836ee4 |
2
.github/workflows/auto-comment-on-label.yaml
vendored
2
.github/workflows/auto-comment-on-label.yaml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
issues: write
|
||||
steps:
|
||||
- name: Add comment
|
||||
uses: peter-evans/create-or-update-comment@d5aa8cd1ea450824d5ae23e44f55efc071b98b44
|
||||
uses: peter-evans/create-or-update-comment@7157823c0f1cb7170b464dc3ffb1555a01ce94c3
|
||||
with:
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
|
||||
2
.github/workflows/container.yaml
vendored
2
.github/workflows/container.yaml
vendored
@@ -45,7 +45,7 @@ jobs:
|
||||
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v4
|
||||
if: github.event_name == 'push'
|
||||
if: github.event_name == 'push' || github.event_name == 'schedule'
|
||||
|
||||
- name: Build and push
|
||||
if: ${{ github.event_name == 'schedule' && env.GH_CR_PAT != null }}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/outbox"
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/activitypub/workerpool"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
@@ -14,15 +15,16 @@ import (
|
||||
|
||||
// Start will initialize and start the federation support.
|
||||
func Start(datastore *data.Datastore) {
|
||||
configRepository := configrepository.Get()
|
||||
persistence.Setup(datastore)
|
||||
workerpool.InitOutboundWorkerPool()
|
||||
inbox.InitInboxWorkerPool()
|
||||
|
||||
// Generate the keys for signing federated activity if needed.
|
||||
if data.GetPrivateKey() == "" {
|
||||
if configRepository.GetPrivateKey() == "" {
|
||||
privateKey, publicKey, err := crypto.GenerateKeys()
|
||||
_ = data.SetPrivateKey(string(privateKey))
|
||||
_ = data.SetPublicKey(string(publicKey))
|
||||
_ = configRepository.SetPrivateKey(string(privateKey))
|
||||
_ = configRepository.SetPublicKey(string(publicKey))
|
||||
if err != nil {
|
||||
log.Errorln("Unable to get private key", err)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// PrivacyAudience represents the audience for an activity.
|
||||
@@ -87,8 +87,10 @@ func MakeActivityDirect(activity vocab.ActivityStreamsCreate, toIRI *url.URL) vo
|
||||
// MakeActivityPublic sets the required properties to make this activity
|
||||
// seen as public.
|
||||
func MakeActivityPublic(activity vocab.ActivityStreamsCreate) vocab.ActivityStreamsCreate {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// TO the public if we're not treating ActivityPub as "private".
|
||||
if !data.GetFederationIsPrivate() {
|
||||
if !configRepository.GetFederationIsPrivate() {
|
||||
public, _ := url.Parse(PUBLIC)
|
||||
|
||||
to := streams.NewActivityStreamsToProperty()
|
||||
@@ -121,7 +123,9 @@ func MakeUpdateActivity(activityID *url.URL) vocab.ActivityStreamsUpdate {
|
||||
activity.SetJSONLDId(id)
|
||||
|
||||
// CC the public if we're not treating ActivityPub as "private".
|
||||
if !data.GetFederationIsPrivate() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationIsPrivate() {
|
||||
public, _ := url.Parse(PUBLIC)
|
||||
cc := streams.NewActivityStreamsCcProperty()
|
||||
cc.AppendIRI(public)
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/owncast/owncast/activitypub/crypto"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -101,11 +101,13 @@ func MakeActorPropertyWithID(idIRI *url.URL) vocab.ActivityStreamsActorProperty
|
||||
|
||||
// MakeServiceForAccount will create a new local actor service with the the provided username.
|
||||
func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
actorIRI := MakeLocalIRIForAccount(accountName)
|
||||
|
||||
person := streams.NewActivityStreamsService()
|
||||
nameProperty := streams.NewActivityStreamsNameProperty()
|
||||
nameProperty.AppendXMLSchemaString(data.GetServerName())
|
||||
nameProperty.AppendXMLSchemaString(configRepository.GetServerName())
|
||||
person.SetActivityStreamsName(nameProperty)
|
||||
|
||||
preferredUsernameProperty := streams.NewActivityStreamsPreferredUsernameProperty()
|
||||
@@ -119,7 +121,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
person.SetActivityStreamsInbox(inboxProp)
|
||||
|
||||
needsFollowApprovalProperty := streams.NewActivityStreamsManuallyApprovesFollowersProperty()
|
||||
needsFollowApprovalProperty.Set(data.GetFederationIsPrivate())
|
||||
needsFollowApprovalProperty.Set(configRepository.GetFederationIsPrivate())
|
||||
person.SetActivityStreamsManuallyApprovesFollowers(needsFollowApprovalProperty)
|
||||
|
||||
outboxIRI := MakeLocalIRIForResource("/user/" + accountName + "/outbox")
|
||||
@@ -152,7 +154,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
publicKeyProp.AppendW3IDSecurityV1PublicKey(publicKeyType)
|
||||
person.SetW3IDSecurityV1PublicKey(publicKeyProp)
|
||||
|
||||
if t, err := data.GetServerInitTime(); t != nil {
|
||||
if t, err := configRepository.GetServerInitTime(); t != nil {
|
||||
publishedDateProp := streams.NewActivityStreamsPublishedProperty()
|
||||
publishedDateProp.Set(t.Time)
|
||||
person.SetActivityStreamsPublished(publishedDateProp)
|
||||
@@ -163,8 +165,8 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
// Profile properties
|
||||
|
||||
// Avatar
|
||||
uniquenessString := data.GetLogoUniquenessString()
|
||||
userAvatarURLString := data.GetServerURL() + "/logo/external"
|
||||
uniquenessString := configRepository.GetLogoUniquenessString()
|
||||
userAvatarURLString := configRepository.GetServerURL() + "/logo/external"
|
||||
userAvatarURL, err := url.Parse(userAvatarURLString)
|
||||
userAvatarURL.RawQuery = "uc=" + uniquenessString
|
||||
if err != nil {
|
||||
@@ -195,14 +197,14 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
|
||||
// Profile bio
|
||||
summaryProperty := streams.NewActivityStreamsSummaryProperty()
|
||||
summaryProperty.AppendXMLSchemaString(data.GetServerSummary())
|
||||
summaryProperty.AppendXMLSchemaString(configRepository.GetServerSummary())
|
||||
person.SetActivityStreamsSummary(summaryProperty)
|
||||
|
||||
// Links
|
||||
if serverURL := data.GetServerURL(); serverURL != "" {
|
||||
if serverURL := configRepository.GetServerURL(); serverURL != "" {
|
||||
addMetadataLinkToProfile(person, "Stream", serverURL)
|
||||
}
|
||||
for _, link := range data.GetSocialHandles() {
|
||||
for _, link := range configRepository.GetSocialHandles() {
|
||||
addMetadataLinkToProfile(person, link.Platform, link.URL)
|
||||
}
|
||||
|
||||
@@ -220,7 +222,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
|
||||
// Tags
|
||||
tagProp := streams.NewActivityStreamsTagProperty()
|
||||
for _, tagString := range data.GetServerMetadataTags() {
|
||||
for _, tagString := range configRepository.GetServerMetadataTags() {
|
||||
hashtag := MakeHashtag(tagString)
|
||||
tagProp.AppendTootHashtag(hashtag)
|
||||
}
|
||||
@@ -229,7 +231,7 @@ func MakeServiceForAccount(accountName string) vocab.ActivityStreamsService {
|
||||
|
||||
// Work around an issue where a single attachment will not serialize
|
||||
// as an array, so add another item to the mix.
|
||||
if len(data.GetSocialHandles()) == 1 {
|
||||
if len(configRepository.GetSocialHandles()) == 1 {
|
||||
addMetadataLinkToProfile(person, "Owncast", "https://owncast.online")
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
func makeFakeService() vocab.ActivityStreamsService {
|
||||
@@ -55,9 +56,11 @@ func TestMain(m *testing.M) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
data.SetupPersistence(dbFile.Name())
|
||||
data.SetServerURL("https://my.cool.site.biz")
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
configRepository.SetServerURL("https://my.cool.site.biz")
|
||||
|
||||
m.Run()
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/go-fed/activity/streams"
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -27,7 +27,9 @@ func MakeRemoteIRIForResource(resourcePath string, host string) (*url.URL, error
|
||||
|
||||
// MakeLocalIRIForResource will create an IRI for the local server.
|
||||
func MakeLocalIRIForResource(resourcePath string) *url.URL {
|
||||
host := data.GetServerURL()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
host := configRepository.GetServerURL()
|
||||
u, err := url.Parse(host)
|
||||
if err != nil {
|
||||
log.Errorln("unable to parse local IRI url", host, err)
|
||||
@@ -41,7 +43,9 @@ func MakeLocalIRIForResource(resourcePath string) *url.URL {
|
||||
|
||||
// MakeLocalIRIForAccount will return a full IRI for the local server account username.
|
||||
func MakeLocalIRIForAccount(account string) *url.URL {
|
||||
host := data.GetServerURL()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
host := configRepository.GetServerURL()
|
||||
u, err := url.Parse(host)
|
||||
if err != nil {
|
||||
log.Errorln("unable to parse local IRI account server url", err)
|
||||
@@ -64,7 +68,9 @@ func Serialize(obj vocab.Type) ([]byte, error) {
|
||||
|
||||
// MakeLocalIRIForStreamURL will return a full IRI for the local server stream url.
|
||||
func MakeLocalIRIForStreamURL() *url.URL {
|
||||
host := data.GetServerURL()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
host := configRepository.GetServerURL()
|
||||
u, err := url.Parse(host)
|
||||
if err != nil {
|
||||
log.Errorln("unable to parse local IRI stream url", err)
|
||||
@@ -78,7 +84,9 @@ func MakeLocalIRIForStreamURL() *url.URL {
|
||||
|
||||
// MakeLocalIRIforLogo will return a full IRI for the local server logo.
|
||||
func MakeLocalIRIforLogo() *url.URL {
|
||||
host := data.GetServerURL()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
host := configRepository.GetServerURL()
|
||||
u, err := url.Parse(host)
|
||||
if err != nil {
|
||||
log.Errorln("unable to parse local IRI stream url", err)
|
||||
@@ -93,7 +101,9 @@ func MakeLocalIRIforLogo() *url.URL {
|
||||
// GetLogoType will return the rel value for the webfinger response and
|
||||
// the default static image is of type png.
|
||||
func GetLogoType() string {
|
||||
imageFilename := data.GetLogoPath()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
imageFilename := configRepository.GetLogoPath()
|
||||
if imageFilename == "" {
|
||||
return "image/png"
|
||||
}
|
||||
|
||||
@@ -9,12 +9,14 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/activitypub/crypto"
|
||||
"github.com/owncast/owncast/activitypub/requests"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// ActorHandler handles requests for a single actor.
|
||||
func ActorHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
@@ -22,7 +24,7 @@ func ActorHandler(w http.ResponseWriter, r *http.Request) {
|
||||
pathComponents := strings.Split(r.URL.Path, "/")
|
||||
accountName := pathComponents[3]
|
||||
|
||||
if _, valid := data.GetFederatedInboxMap()[accountName]; !valid {
|
||||
if _, valid := configRepository.GetFederatedInboxMap()[accountName]; !valid {
|
||||
// User is not valid
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/crypto"
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/activitypub/requests"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -145,7 +145,9 @@ func getFollowersPage(page string, r *http.Request) (vocab.ActivityStreamsOrdere
|
||||
}
|
||||
|
||||
func createPageURL(r *http.Request, page *string) (*url.URL, error) {
|
||||
domain := data.GetServerURL()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
domain := configRepository.GetServerURL()
|
||||
if domain == "" {
|
||||
return nil, errors.New("unable to get server URL")
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/activitypub/inbox"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -22,7 +22,9 @@ func InboxHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func acceptInboxRequest(w http.ResponseWriter, r *http.Request) {
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
@@ -39,7 +41,7 @@ func acceptInboxRequest(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// The account this request is for must match the account name we have set
|
||||
// for federation.
|
||||
if forLocalAccount != data.GetFederationUsername() {
|
||||
if forLocalAccount != configRepository.GetFederationUsername() {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/activitypub/requests"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -25,12 +25,14 @@ func NodeInfoController(w http.ResponseWriter, r *http.Request) {
|
||||
Links []links `json:"links"`
|
||||
}
|
||||
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
serverURL := data.GetServerURL()
|
||||
serverURL := configRepository.GetServerURL()
|
||||
if serverURL == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@@ -89,7 +91,9 @@ func NodeInfoV2Controller(w http.ResponseWriter, r *http.Request) {
|
||||
Metadata metadata `json:"metadata"`
|
||||
}
|
||||
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
@@ -117,7 +121,7 @@ func NodeInfoV2Controller(w http.ResponseWriter, r *http.Request) {
|
||||
OpenRegistrations: false,
|
||||
Protocols: []string{"activitypub"},
|
||||
Metadata: metadata{
|
||||
ChatEnabled: !data.GetChatDisabled(),
|
||||
ChatEnabled: !configRepository.GetChatDisabled(),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -163,12 +167,14 @@ func XNodeInfo2Controller(w http.ResponseWriter, r *http.Request) {
|
||||
OpenRegistrations bool `json:"openRegistrations"`
|
||||
}
|
||||
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
serverURL := data.GetServerURL()
|
||||
serverURL := configRepository.GetServerURL()
|
||||
if serverURL == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@@ -178,7 +184,7 @@ func XNodeInfo2Controller(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
res := &response{
|
||||
Organization: Organization{
|
||||
Name: data.GetServerName(),
|
||||
Name: configRepository.GetServerName(),
|
||||
Contact: serverURL,
|
||||
},
|
||||
Server: Server{
|
||||
@@ -232,12 +238,14 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
|
||||
InvitesEnabled bool `json:"invites_enabled"`
|
||||
}
|
||||
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
serverURL := data.GetServerURL()
|
||||
serverURL := configRepository.GetServerURL()
|
||||
if serverURL == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
@@ -254,9 +262,9 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
res := response{
|
||||
URI: serverURL,
|
||||
Title: data.GetServerName(),
|
||||
ShortDescription: data.GetServerSummary(),
|
||||
Description: data.GetServerSummary(),
|
||||
Title: configRepository.GetServerName(),
|
||||
ShortDescription: configRepository.GetServerSummary(),
|
||||
Description: configRepository.GetServerSummary(),
|
||||
Version: config.GetReleaseString(),
|
||||
Stats: Stats{
|
||||
UserCount: 1,
|
||||
@@ -275,7 +283,9 @@ func InstanceV1Controller(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func writeResponse(payload interface{}, w http.ResponseWriter) error {
|
||||
accountName := data.GetDefaultFederationUsername()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
accountName := configRepository.GetDefaultFederationUsername()
|
||||
actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
|
||||
publicKey := crypto.GetPublicKey(actorIRI)
|
||||
|
||||
@@ -284,13 +294,15 @@ func writeResponse(payload interface{}, w http.ResponseWriter) error {
|
||||
|
||||
// HostMetaController points to webfinger.
|
||||
func HostMetaController(w http.ResponseWriter, r *http.Request) {
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
log.Debugln("host meta request rejected! Federation is not enabled")
|
||||
return
|
||||
}
|
||||
|
||||
serverURL := data.GetServerURL()
|
||||
serverURL := configRepository.GetServerURL()
|
||||
if serverURL == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
|
||||
@@ -8,31 +8,33 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/crypto"
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/activitypub/requests"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// ObjectHandler handles requests for a single federated ActivityPub object.
|
||||
func ObjectHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// If private federation mode is enabled do not allow access to objects.
|
||||
if data.GetFederationIsPrivate() {
|
||||
if configRepository.GetFederationIsPrivate() {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
iri := strings.Join([]string{strings.TrimSuffix(data.GetServerURL(), "/"), r.URL.Path}, "")
|
||||
iri := strings.Join([]string{strings.TrimSuffix(configRepository.GetServerURL(), "/"), r.URL.Path}, "")
|
||||
object, _, _, err := persistence.GetObjectByIRI(iri)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
accountName := data.GetDefaultFederationUsername()
|
||||
accountName := configRepository.GetDefaultFederationUsername()
|
||||
actorIRI := apmodels.MakeLocalIRIForAccount(accountName)
|
||||
publicKey := crypto.GetPublicKey(actorIRI)
|
||||
|
||||
|
||||
@@ -6,20 +6,22 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// WebfingerHandler will handle webfinger lookup requests.
|
||||
func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if !data.GetFederationEnabled() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
log.Debugln("webfinger request rejected! Federation is not enabled")
|
||||
return
|
||||
}
|
||||
|
||||
instanceHostURL := data.GetServerURL()
|
||||
instanceHostURL := configRepository.GetServerURL()
|
||||
if instanceHostURL == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
log.Warnln("webfinger request rejected! Federation is enabled but server URL is empty.")
|
||||
@@ -29,7 +31,7 @@ func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
instanceHostString := utils.GetHostnameFromURLString(instanceHostURL)
|
||||
if instanceHostString == "" {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
log.Warnln("webfinger request rejected! Federation is enabled but server URL is not set properly. data.GetServerURL(): " + data.GetServerURL())
|
||||
log.Warnln("webfinger request rejected! Federation is enabled but server URL is not set properly. data.GetServerURL(): " + configRepository.GetServerURL())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -51,7 +53,7 @@ func WebfingerHandler(w http.ResponseWriter, r *http.Request) {
|
||||
host := userComponents[1]
|
||||
user := userComponents[0]
|
||||
|
||||
if _, valid := data.GetFederatedInboxMap()[user]; !valid {
|
||||
if _, valid := configRepository.GetFederatedInboxMap()[user]; !valid {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
log.Debugln("webfinger request rejected! Invalid user: " + user)
|
||||
return
|
||||
|
||||
@@ -8,13 +8,15 @@ import (
|
||||
"errors"
|
||||
"net/url"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetPublicKey will return the public key for the provided actor.
|
||||
func GetPublicKey(actorIRI *url.URL) PublicKey {
|
||||
key := data.GetPublicKey()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
key := configRepository.GetPublicKey()
|
||||
idURL, err := url.Parse(actorIRI.String() + "#main-key")
|
||||
if err != nil {
|
||||
log.Errorln("unable to parse actor iri string", idURL, err)
|
||||
@@ -29,7 +31,9 @@ func GetPublicKey(actorIRI *url.URL) PublicKey {
|
||||
|
||||
// GetPrivateKey will return the internal server private key.
|
||||
func GetPrivateKey() *rsa.PrivateKey {
|
||||
key := data.GetPrivateKey()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
key := configRepository.GetPrivateKey()
|
||||
|
||||
block, _ := pem.Decode([]byte(key))
|
||||
if block == nil {
|
||||
|
||||
@@ -7,17 +7,19 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/resolvers"
|
||||
"github.com/owncast/owncast/core/chat"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
func handleEngagementActivity(eventType events.EventType, isLiveNotification bool, actorReference vocab.ActivityStreamsActorProperty, action string) error {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// Do nothing if displaying engagement actions has been turned off.
|
||||
if !data.GetFederationShowEngagement() {
|
||||
if !configRepository.GetFederationShowEngagement() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Do nothing if chat is disabled
|
||||
if data.GetChatDisabled() {
|
||||
if configRepository.GetChatDisabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -36,11 +38,11 @@ func handleEngagementActivity(eventType events.EventType, isLiveNotification boo
|
||||
if isLiveNotification && action == events.FediverseEngagementLike {
|
||||
suffix = "liked that this stream went live."
|
||||
} else if action == events.FediverseEngagementLike {
|
||||
suffix = fmt.Sprintf("liked a post from %s.", data.GetServerName())
|
||||
suffix = fmt.Sprintf("liked a post from %s.", configRepository.GetServerName())
|
||||
} else if isLiveNotification && action == events.FediverseEngagementRepost {
|
||||
suffix = "shared this stream with their followers."
|
||||
} else if action == events.FediverseEngagementRepost {
|
||||
suffix = fmt.Sprintf("shared a post from %s.", data.GetServerName())
|
||||
suffix = fmt.Sprintf("shared a post from %s.", configRepository.GetServerName())
|
||||
} else if action == events.FediverseEngagementFollow {
|
||||
suffix = "followed this stream."
|
||||
} else {
|
||||
|
||||
@@ -10,13 +10,15 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/requests"
|
||||
"github.com/owncast/owncast/activitypub/resolvers"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsFollow) error {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
follow, err := resolvers.MakeFollowRequest(c, activity)
|
||||
if err != nil {
|
||||
log.Errorln("unable to create follow inbox request", err)
|
||||
@@ -27,7 +29,7 @@ func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsF
|
||||
return fmt.Errorf("unable to handle request")
|
||||
}
|
||||
|
||||
approved := !data.GetFederationIsPrivate()
|
||||
approved := !configRepository.GetFederationIsPrivate()
|
||||
|
||||
followRequest := *follow
|
||||
|
||||
@@ -36,7 +38,7 @@ func handleFollowInboxRequest(c context.Context, activity vocab.ActivityStreamsF
|
||||
return err
|
||||
}
|
||||
|
||||
localAccountName := data.GetDefaultFederationUsername()
|
||||
localAccountName := configRepository.GetDefaultFederationUsername()
|
||||
|
||||
if approved {
|
||||
if err := requests.SendFollowAccept(follow.Inbox, activity, localAccountName); err != nil {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/activitypub/resolvers"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -131,7 +131,9 @@ func Verify(request *http.Request) (bool, error) {
|
||||
}
|
||||
|
||||
func isBlockedDomain(domain string) bool {
|
||||
blockedDomains := data.GetBlockedFederatedDomains()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
blockedDomains := configRepository.GetBlockedFederatedDomains()
|
||||
|
||||
for _, blockedDomain := range blockedDomains {
|
||||
if strings.Contains(domain, blockedDomain) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/activitypub/persistence"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
func makeFakePerson() vocab.ActivityStreamsPerson {
|
||||
@@ -49,21 +50,24 @@ func makeFakePerson() vocab.ActivityStreamsPerson {
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
data.SetupPersistence(":memory:")
|
||||
data.SetServerURL("https://my.cool.site.biz")
|
||||
configRepository := configrepository.Get()
|
||||
configRepository.SetServerURL("https://my.cool.site.biz")
|
||||
persistence.Setup(data.GetDatastore())
|
||||
m.Run()
|
||||
}
|
||||
|
||||
func TestBlockedDomains(t *testing.T) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
person := makeFakePerson()
|
||||
|
||||
data.SetBlockedFederatedDomains([]string{"freedom.eagle", "guns.life"})
|
||||
configRepository.SetBlockedFederatedDomains([]string{"freedom.eagle", "guns.life"})
|
||||
|
||||
if len(data.GetBlockedFederatedDomains()) != 2 {
|
||||
if len(configRepository.GetBlockedFederatedDomains()) != 2 {
|
||||
t.Error("Blocked federated domains is not set correctly")
|
||||
}
|
||||
|
||||
for _, domain := range data.GetBlockedFederatedDomains() {
|
||||
for _, domain := range configRepository.GetBlockedFederatedDomains() {
|
||||
if domain == person.GetJSONLDId().GetIRI().Host {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ import (
|
||||
"github.com/owncast/owncast/activitypub/resolvers"
|
||||
"github.com/owncast/owncast/activitypub/webfinger"
|
||||
"github.com/owncast/owncast/activitypub/workerpool"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/teris-io/shortid"
|
||||
@@ -27,7 +27,9 @@ import (
|
||||
|
||||
// SendLive will send all followers the message saying you started a live stream.
|
||||
func SendLive() error {
|
||||
textContent := data.GetFederationGoLiveMessage()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
textContent := configRepository.GetFederationGoLiveMessage()
|
||||
|
||||
// If the message is empty then do not send it.
|
||||
if textContent == "" {
|
||||
@@ -38,7 +40,7 @@ func SendLive() error {
|
||||
reg := regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
|
||||
tagProp := streams.NewActivityStreamsTagProperty()
|
||||
for _, tagString := range data.GetServerMetadataTags() {
|
||||
for _, tagString := range configRepository.GetServerMetadataTags() {
|
||||
tagWithoutSpecialCharacters := reg.ReplaceAllString(tagString, "")
|
||||
hashtag := apmodels.MakeHashtag(tagWithoutSpecialCharacters)
|
||||
tagProp.AppendTootHashtag(hashtag)
|
||||
@@ -57,15 +59,15 @@ func SendLive() error {
|
||||
tagsString := strings.Join(tagStrings, " ")
|
||||
|
||||
var streamTitle string
|
||||
if title := data.GetStreamTitle(); title != "" {
|
||||
if title := configRepository.GetStreamTitle(); title != "" {
|
||||
streamTitle = fmt.Sprintf("<p>%s</p>", title)
|
||||
}
|
||||
textContent = fmt.Sprintf("<p>%s</p>%s<p>%s</p><p><a href=\"%s\">%s</a></p>", textContent, streamTitle, tagsString, data.GetServerURL(), data.GetServerURL())
|
||||
textContent = fmt.Sprintf("<p>%s</p>%s<p>%s</p><p><a href=\"%s\">%s</a></p>", textContent, streamTitle, tagsString, configRepository.GetServerURL(), configRepository.GetServerURL())
|
||||
|
||||
activity, _, note, noteID := createBaseOutboundMessage(textContent)
|
||||
|
||||
// To the public if we're not treating ActivityPub as "private".
|
||||
if !data.GetFederationIsPrivate() {
|
||||
if !configRepository.GetFederationIsPrivate() {
|
||||
note = apmodels.MakeNotePublic(note)
|
||||
activity = apmodels.MakeActivityPublic(activity)
|
||||
}
|
||||
@@ -73,7 +75,7 @@ func SendLive() error {
|
||||
note.SetActivityStreamsTag(tagProp)
|
||||
|
||||
// Attach an image along with the Federated message.
|
||||
previewURL, err := url.Parse(data.GetServerURL())
|
||||
previewURL, err := url.Parse(configRepository.GetServerURL())
|
||||
if err == nil {
|
||||
var imageToAttach string
|
||||
var mediaType string
|
||||
@@ -94,7 +96,7 @@ func SendLive() error {
|
||||
}
|
||||
}
|
||||
|
||||
if data.GetNSFW() {
|
||||
if configRepository.GetNSFW() {
|
||||
// Mark content as sensitive.
|
||||
sensitive := streams.NewActivityStreamsSensitiveProperty()
|
||||
sensitive.AppendXMLSchemaBoolean(true)
|
||||
@@ -151,6 +153,8 @@ func SendDirectMessageToAccount(textContent, account string) error {
|
||||
|
||||
// SendPublicMessage will send a public message to all followers.
|
||||
func SendPublicMessage(textContent string) error {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
originalContent := textContent
|
||||
textContent = utils.RenderSimpleMarkdown(textContent)
|
||||
|
||||
@@ -173,7 +177,7 @@ func SendPublicMessage(textContent string) error {
|
||||
activity, _, note, noteID := createBaseOutboundMessage(textContent)
|
||||
note.SetActivityStreamsTag(tagProp)
|
||||
|
||||
if !data.GetFederationIsPrivate() {
|
||||
if !configRepository.GetFederationIsPrivate() {
|
||||
note = apmodels.MakeNotePublic(note)
|
||||
activity = apmodels.MakeActivityPublic(activity)
|
||||
}
|
||||
@@ -197,7 +201,8 @@ func SendPublicMessage(textContent string) error {
|
||||
|
||||
// nolint: unparam
|
||||
func createBaseOutboundMessage(textContent string) (vocab.ActivityStreamsCreate, string, vocab.ActivityStreamsNote, string) {
|
||||
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
|
||||
configRepository := configrepository.Get()
|
||||
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
|
||||
noteID := shortid.MustGenerate()
|
||||
noteIRI := apmodels.MakeLocalIRIForResource(noteID)
|
||||
id := shortid.MustGenerate()
|
||||
@@ -218,7 +223,8 @@ func getHashtagLinkHTMLFromTagString(baseHashtag string) string {
|
||||
|
||||
// SendToFollowers will send an arbitrary payload to all follower inboxes.
|
||||
func SendToFollowers(payload []byte) error {
|
||||
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
|
||||
configRepository := configrepository.Get()
|
||||
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
|
||||
|
||||
followers, _, err := persistence.GetFederationFollowers(-1, 0)
|
||||
if err != nil {
|
||||
@@ -241,7 +247,8 @@ func SendToFollowers(payload []byte) error {
|
||||
|
||||
// SendToUser will send a payload to a single specific inbox.
|
||||
func SendToUser(inbox *url.URL, payload []byte) error {
|
||||
localActor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
|
||||
configRepository := configrepository.Get()
|
||||
localActor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
|
||||
|
||||
req, err := requests.CreateSignedRequest(payload, inbox, localActor)
|
||||
if err != nil {
|
||||
@@ -255,8 +262,10 @@ func SendToUser(inbox *url.URL, payload []byte) error {
|
||||
|
||||
// UpdateFollowersWithAccountUpdates will send an update to all followers alerting of a profile update.
|
||||
func UpdateFollowersWithAccountUpdates() error {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// Don't do anything if federation is disabled.
|
||||
if !data.GetFederationEnabled() {
|
||||
if !configRepository.GetFederationEnabled() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -265,7 +274,7 @@ func UpdateFollowersWithAccountUpdates() error {
|
||||
activity := apmodels.MakeUpdateActivity(objectID)
|
||||
|
||||
actor := streams.NewActivityStreamsPerson()
|
||||
actorID := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
|
||||
actorID := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
|
||||
actorIDProperty := streams.NewJSONLDIdProperty()
|
||||
actorIDProperty.Set(actorID)
|
||||
actor.SetJSONLDId(actorIDProperty)
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"github.com/go-fed/activity/streams/vocab"
|
||||
"github.com/owncast/owncast/activitypub/apmodels"
|
||||
"github.com/owncast/owncast/activitypub/crypto"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -47,11 +47,12 @@ func Resolve(c context.Context, data []byte, callbacks ...interface{}) error {
|
||||
|
||||
// ResolveIRI will resolve an IRI ahd call the correct callback for the resolved type.
|
||||
func ResolveIRI(c context.Context, iri string, callbacks ...interface{}) error {
|
||||
configRepository := configrepository.Get()
|
||||
log.Debugln("Resolving", iri)
|
||||
|
||||
req, _ := http.NewRequest(http.MethodGet, iri, nil)
|
||||
|
||||
actor := apmodels.MakeLocalIRIForAccount(data.GetDefaultFederationUsername())
|
||||
actor := apmodels.MakeLocalIRIForAccount(configRepository.GetDefaultFederationUsername())
|
||||
if err := crypto.SignRequest(req, nil, actor); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -47,6 +47,8 @@ func setupExpiredRequestPruner() {
|
||||
|
||||
// StartAuthFlow will begin the IndieAuth flow by generating an auth request.
|
||||
func StartAuthFlow(authHost, userID, accessToken, displayName string) (*url.URL, error) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// Limit the number of pending requests
|
||||
if len(pendingAuthRequests) >= maxPendingRequests {
|
||||
return nil, errors.New("Please try again later. Too many pending requests.")
|
||||
@@ -68,7 +70,7 @@ func StartAuthFlow(authHost, userID, accessToken, displayName string) (*url.URL,
|
||||
return nil, errors.New("only servers secured with https are supported")
|
||||
}
|
||||
|
||||
serverURL := data.GetServerURL()
|
||||
serverURL := configRepository.GetServerURL()
|
||||
if serverURL == "" {
|
||||
return nil, errors.New("Owncast server URL must be set when using auth")
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/teris-io/shortid"
|
||||
)
|
||||
@@ -70,6 +70,8 @@ func StartServerAuth(clientID, redirectURI, codeChallenge, state, me string) (*S
|
||||
// CompleteServerAuth will verify that the values provided in the final step
|
||||
// of the IndieAuth flow are correct, and return some basic profile info.
|
||||
func CompleteServerAuth(code, redirectURI, clientID string, codeVerifier string) (*ServerProfileResponse, error) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
request, pending := pendingServerAuthRequests[code]
|
||||
if !pending {
|
||||
return nil, errors.New("no pending authentication request")
|
||||
@@ -89,11 +91,11 @@ func CompleteServerAuth(code, redirectURI, clientID string, codeVerifier string)
|
||||
}
|
||||
|
||||
response := ServerProfileResponse{
|
||||
Me: data.GetServerURL(),
|
||||
Me: configRepository.GetServerURL(),
|
||||
Profile: ServerProfile{
|
||||
Name: data.GetServerName(),
|
||||
URL: data.GetServerURL(),
|
||||
Photo: fmt.Sprintf("%s/%s", data.GetServerURL(), data.GetLogoPath()),
|
||||
Name: configRepository.GetServerName(),
|
||||
URL: configRepository.GetServerURL(),
|
||||
Photo: fmt.Sprintf("%s/%s", configRepository.GetServerURL(), configRepository.GetLogoPath()),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -23,6 +23,8 @@ var (
|
||||
func Start(getStatusFunc func() models.Status) error {
|
||||
setupPersistence()
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
getStatus = getStatusFunc
|
||||
_server = NewChat()
|
||||
|
||||
@@ -35,7 +37,7 @@ func Start(getStatusFunc func() models.Status) error {
|
||||
Help: "The number of chat messages incremented over time.",
|
||||
ConstLabels: map[string]string{
|
||||
"version": config.VersionNumber,
|
||||
"host": data.GetServerURL(),
|
||||
"host": configRepository.GetServerURL(),
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/services/geoip"
|
||||
)
|
||||
|
||||
@@ -133,7 +133,9 @@ func (c *Client) readPump() {
|
||||
}
|
||||
|
||||
// Check if this message passes the optional language filter
|
||||
if data.GetChatSlurFilterEnabled() && !c.messageFilter.Allow(string(message)) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if configRepository.GetChatSlurFilterEnabled() && !c.messageFilter.Allow(string(message)) {
|
||||
c.sendAction("Sorry, that message contained language that is not allowed in this chat.")
|
||||
continue
|
||||
}
|
||||
@@ -209,9 +211,11 @@ func (c *Client) close() {
|
||||
}
|
||||
|
||||
func (c *Client) passesRateLimit() bool {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// If spam rate limiting is disabled, or the user is a moderator, always
|
||||
// allow the message.
|
||||
if !data.GetChatSpamProtectionEnabled() || c.User.IsModerator() {
|
||||
if !configRepository.GetChatSpamProtectionEnabled() || c.User.IsModerator() {
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/webhooks"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/persistence/userrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -22,10 +22,12 @@ func (s *Server) userNameChanged(eventData chatClientEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
proposedUsername := receivedEvent.NewName
|
||||
|
||||
// Check if name is on the blocklist
|
||||
blocklist := data.GetForbiddenUsernameList()
|
||||
blocklist := configRepository.GetForbiddenUsernameList()
|
||||
|
||||
// Names have a max length
|
||||
proposedUsername = utils.MakeSafeStringOfLength(proposedUsername, config.MaxChatDisplayNameLength)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package events
|
||||
|
||||
import "github.com/owncast/owncast/core/data"
|
||||
import (
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// FediverseEngagementEvent is a message displayed in chat on representing an action on the Fediverse.
|
||||
type FediverseEngagementEvent struct {
|
||||
@@ -13,6 +15,8 @@ type FediverseEngagementEvent struct {
|
||||
|
||||
// GetBroadcastPayload will return the object to send to all chat users.
|
||||
func (e *FediverseEngagementEvent) GetBroadcastPayload() EventPayload {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
return EventPayload{
|
||||
"id": e.ID,
|
||||
"timestamp": e.Timestamp,
|
||||
@@ -22,7 +26,7 @@ func (e *FediverseEngagementEvent) GetBroadcastPayload() EventPayload {
|
||||
"title": e.UserAccountName,
|
||||
"link": e.Link,
|
||||
"user": EventPayload{
|
||||
"displayName": data.GetServerName(),
|
||||
"displayName": configRepository.GetServerName(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package events
|
||||
|
||||
import "github.com/owncast/owncast/core/data"
|
||||
import (
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// SystemMessageEvent is a message displayed in chat on behalf of the server.
|
||||
type SystemMessageEvent struct {
|
||||
@@ -10,13 +12,15 @@ type SystemMessageEvent struct {
|
||||
|
||||
// GetBroadcastPayload will return the object to send to all chat users.
|
||||
func (e *SystemMessageEvent) GetBroadcastPayload() EventPayload {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
return EventPayload{
|
||||
"id": e.ID,
|
||||
"timestamp": e.Timestamp,
|
||||
"body": e.Body,
|
||||
"type": SystemMessageSent,
|
||||
"user": EventPayload{
|
||||
"displayName": data.GetServerName(),
|
||||
"displayName": configRepository.GetServerName(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/authrepository"
|
||||
"github.com/owncast/owncast/persistence/tables"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -24,7 +25,9 @@ const (
|
||||
func setupPersistence() {
|
||||
_datastore = data.GetDatastore()
|
||||
tables.CreateMessagesTable(_datastore.DB)
|
||||
data.CreateBanIPTable(_datastore.DB)
|
||||
|
||||
authRepository := authrepository.Get()
|
||||
authRepository.CreateBanIPTable(_datastore.DB)
|
||||
|
||||
chatDataPruner := time.NewTicker(5 * time.Minute)
|
||||
go func() {
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/webhooks"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/authrepository"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/persistence/userrepository"
|
||||
"github.com/owncast/owncast/services/geoip"
|
||||
"github.com/owncast/owncast/utils"
|
||||
@@ -95,7 +96,9 @@ func (s *Server) Addclient(conn *websocket.Conn, user *models.User, accessToken
|
||||
ConnectedAt: time.Now(),
|
||||
}
|
||||
|
||||
shouldSendJoinedMessages := data.GetChatJoinPartMessagesEnabled()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
shouldSendJoinedMessages := configRepository.GetChatJoinPartMessagesEnabled()
|
||||
|
||||
// If there are existing clients connected for this user do not send
|
||||
// a user joined message. Do not put this under a mutex, as
|
||||
@@ -186,8 +189,10 @@ func (s *Server) sendUserPartedMessage(c *Client) {
|
||||
userPartEvent.User = c.User
|
||||
userPartEvent.ClientID = c.Id
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// If part messages are disabled.
|
||||
if data.GetChatJoinPartMessagesEnabled() {
|
||||
if configRepository.GetChatJoinPartMessagesEnabled() {
|
||||
if err := s.Broadcast(userPartEvent.GetBroadcastPayload()); err != nil {
|
||||
log.Errorln("error sending chat part message", err)
|
||||
}
|
||||
@@ -198,14 +203,17 @@ func (s *Server) sendUserPartedMessage(c *Client) {
|
||||
|
||||
// HandleClientConnection is fired when a single client connects to the websocket.
|
||||
func (s *Server) HandleClientConnection(w http.ResponseWriter, r *http.Request) {
|
||||
if data.GetChatDisabled() {
|
||||
configRepository := configrepository.Get()
|
||||
authRepository := authrepository.Get()
|
||||
|
||||
if configRepository.GetChatDisabled() {
|
||||
_, _ = w.Write([]byte(events.ChatDisabled))
|
||||
return
|
||||
}
|
||||
|
||||
ipAddress := utils.GetIPAddressFromRequest(r)
|
||||
// Check if this client's IP address is banned. If so send a rejection.
|
||||
if blocked, err := data.IsIPAddressBanned(ipAddress); blocked {
|
||||
if blocked, err := authRepository.IsIPAddressBanned(ipAddress); blocked {
|
||||
log.Debugln("Client ip address has been blocked. Rejecting.")
|
||||
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
@@ -377,12 +385,14 @@ func SendActionToUser(userID string, text string) error {
|
||||
}
|
||||
|
||||
func (s *Server) eventReceived(event chatClientEvent) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
c := event.client
|
||||
u := c.User
|
||||
|
||||
// If established chat user only mode is enabled and the user is not old
|
||||
// enough then reject this event and send them an informative message.
|
||||
if u != nil && data.GetChatEstbalishedUsersOnlyMode() && time.Since(event.client.User.CreatedAt) < config.GetDefaults().ChatEstablishedUserModeTimeDuration && !u.IsModerator() {
|
||||
if u != nil && configRepository.GetChatEstbalishedUsersOnlyMode() && time.Since(event.client.User.CreatedAt) < config.GetDefaults().ChatEstablishedUserModeTimeDuration && !u.IsModerator() {
|
||||
s.sendActionToClient(c, "You have not been an established chat participant long enough to take part in chat. Please enjoy the stream and try again later.")
|
||||
return
|
||||
}
|
||||
@@ -409,10 +419,12 @@ func (s *Server) eventReceived(event chatClientEvent) {
|
||||
}
|
||||
|
||||
func (s *Server) sendWelcomeMessageToClient(c *Client) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
// Add an artificial delay so people notice this message come in.
|
||||
time.Sleep(7 * time.Second)
|
||||
|
||||
welcomeMessage := utils.RenderSimpleMarkdown(data.GetServerWelcomeMessage())
|
||||
welcomeMessage := utils.RenderSimpleMarkdown(configRepository.GetServerWelcomeMessage())
|
||||
|
||||
if welcomeMessage != "" {
|
||||
s.sendSystemMessageToClient(c, welcomeMessage)
|
||||
@@ -420,7 +432,9 @@ func (s *Server) sendWelcomeMessageToClient(c *Client) {
|
||||
}
|
||||
|
||||
func (s *Server) sendAllWelcomeMessage() {
|
||||
welcomeMessage := utils.RenderSimpleMarkdown(data.GetServerWelcomeMessage())
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
welcomeMessage := utils.RenderSimpleMarkdown(configRepository.GetServerWelcomeMessage())
|
||||
|
||||
if welcomeMessage != "" {
|
||||
clientMessage := events.SystemMessageEvent{
|
||||
|
||||
15
core/core.go
15
core/core.go
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/owncast/owncast/core/webhooks"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/notifications"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/persistence/tables"
|
||||
"github.com/owncast/owncast/utils"
|
||||
"github.com/owncast/owncast/yp"
|
||||
@@ -34,10 +35,10 @@ var (
|
||||
// Start starts up the core processing.
|
||||
func Start() error {
|
||||
resetDirectories()
|
||||
configRepository := configrepository.Get()
|
||||
// configRepository.PopulateDefaults()
|
||||
|
||||
data.PopulateDefaults()
|
||||
|
||||
if err := data.VerifySettings(); err != nil {
|
||||
if err := configRepository.VerifySettings(); err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
@@ -75,7 +76,7 @@ func Start() error {
|
||||
// start the rtmp server
|
||||
go rtmp.Start(setStreamAsConnected, setBroadcaster)
|
||||
|
||||
rtmpPort := data.GetRTMPPortNumber()
|
||||
rtmpPort := configRepository.GetRTMPPortNumber()
|
||||
if rtmpPort != 1935 {
|
||||
log.Infof("RTMP is accepting inbound streams on port %d.", rtmpPort)
|
||||
}
|
||||
@@ -113,7 +114,8 @@ func transitionToOfflineVideoStreamContent() {
|
||||
go _transcoder.Start(false)
|
||||
|
||||
// Copy the logo to be the thumbnail
|
||||
logo := data.GetLogoPath()
|
||||
configRepository := configrepository.Get()
|
||||
logo := configRepository.GetLogoPath()
|
||||
dst := filepath.Join(config.TempDir, "thumbnail.jpg")
|
||||
if err = utils.Copy(filepath.Join("data", logo), dst); err != nil {
|
||||
log.Warnln(err)
|
||||
@@ -130,7 +132,8 @@ func resetDirectories() {
|
||||
utils.CleanupDirectory(config.HLSStoragePath)
|
||||
|
||||
// Remove the previous thumbnail
|
||||
logo := data.GetLogoPath()
|
||||
configRepository := configrepository.Get()
|
||||
logo := configRepository.GetLogoPath()
|
||||
if utils.DoesFileExists(logo) {
|
||||
err := utils.Copy(path.Join("data", logo), filepath.Join(config.DataDirectory, "thumbnail.jpg"))
|
||||
if err != nil {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
package data
|
||||
|
||||
// GetFederatedInboxMap is a mapping between account names and their outbox.
|
||||
func GetFederatedInboxMap() map[string]string {
|
||||
return map[string]string{
|
||||
GetDefaultFederationUsername(): GetDefaultFederationUsername(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetDefaultFederationUsername will return the username used for sending federation activities.
|
||||
func GetDefaultFederationUsername() string {
|
||||
return GetFederationUsername()
|
||||
}
|
||||
1027
core/data/config.go
1027
core/data/config.go
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
package data
|
||||
|
||||
// GetPublicKey will return the public key.
|
||||
func GetPublicKey() string {
|
||||
value, _ := _datastore.GetString(publicKeyKey)
|
||||
return value
|
||||
}
|
||||
|
||||
// SetPublicKey will save the public key.
|
||||
func SetPublicKey(key string) error {
|
||||
return _datastore.SetString(publicKeyKey, key)
|
||||
}
|
||||
|
||||
// GetPrivateKey will return the private key.
|
||||
func GetPrivateKey() string {
|
||||
value, _ := _datastore.GetString(privateKeyKey)
|
||||
return value
|
||||
}
|
||||
|
||||
// SetPrivateKey will save the private key.
|
||||
func SetPrivateKey(key string) error {
|
||||
return _datastore.SetString(privateKeyKey, key)
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/owncast/owncast/models"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
@@ -89,7 +91,7 @@ func TestCustomType(t *testing.T) {
|
||||
}
|
||||
|
||||
// Save config entry to the database
|
||||
if err := _datastore.Save(ConfigEntry{&testStruct, testKey}); err != nil {
|
||||
if err := _datastore.Save(models.ConfigEntry{&testStruct, testKey}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -101,7 +103,7 @@ func TestCustomType(t *testing.T) {
|
||||
|
||||
// Get a typed struct out of it
|
||||
var testResult TestStruct
|
||||
if err := entryResult.getObject(&testResult); err != nil {
|
||||
if err := entryResult.GetObject(&testResult); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -121,7 +123,7 @@ func TestStringMap(t *testing.T) {
|
||||
}
|
||||
|
||||
// Save config entry to the database
|
||||
if err := _datastore.Save(ConfigEntry{&testMap, testKey}); err != nil {
|
||||
if err := _datastore.Save(models.ConfigEntry{Value: &testMap, Key: testKey}); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -131,7 +133,7 @@ func TestStringMap(t *testing.T) {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
testResult, err := entryResult.getStringMap()
|
||||
testResult, err := entryResult.GetStringMap()
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
@@ -5,12 +5,11 @@ import (
|
||||
"database/sql"
|
||||
"encoding/gob"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
// sqlite requires a blank import.
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/db"
|
||||
"github.com/owncast/owncast/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
@@ -21,7 +20,8 @@ type Datastore struct {
|
||||
DbLock *sync.Mutex
|
||||
}
|
||||
|
||||
func (ds *Datastore) warmCache() {
|
||||
// WarmCache pre-caches all configuration values in memory.
|
||||
func (ds *Datastore) WarmCache() {
|
||||
log.Traceln("Warming config value cache")
|
||||
|
||||
res, err := ds.DB.Query("SELECT key, value FROM datastore")
|
||||
@@ -46,10 +46,10 @@ func (ds *Datastore) GetQueries() *db.Queries {
|
||||
}
|
||||
|
||||
// Get will query the database for the key and return the entry.
|
||||
func (ds *Datastore) Get(key string) (ConfigEntry, error) {
|
||||
func (ds *Datastore) Get(key string) (models.ConfigEntry, error) {
|
||||
cachedValue, err := ds.GetCachedValue(key)
|
||||
if err == nil {
|
||||
return ConfigEntry{
|
||||
return models.ConfigEntry{
|
||||
Key: key,
|
||||
Value: cachedValue,
|
||||
}, nil
|
||||
@@ -60,10 +60,10 @@ func (ds *Datastore) Get(key string) (ConfigEntry, error) {
|
||||
|
||||
row := ds.DB.QueryRow("SELECT key, value FROM datastore WHERE key = ? LIMIT 1", key)
|
||||
if err := row.Scan(&resultKey, &resultValue); err != nil {
|
||||
return ConfigEntry{}, err
|
||||
return models.ConfigEntry{}, err
|
||||
}
|
||||
|
||||
result := ConfigEntry{
|
||||
result := models.ConfigEntry{
|
||||
Key: resultKey,
|
||||
Value: resultValue,
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func (ds *Datastore) Get(key string) (ConfigEntry, error) {
|
||||
}
|
||||
|
||||
// Save will save the ConfigEntry to the database.
|
||||
func (ds *Datastore) Save(e ConfigEntry) error {
|
||||
func (ds *Datastore) Save(e models.ConfigEntry) error {
|
||||
ds.DbLock.Lock()
|
||||
defer ds.DbLock.Unlock()
|
||||
|
||||
@@ -93,7 +93,6 @@ func (ds *Datastore) Save(e ConfigEntry) error {
|
||||
return err
|
||||
}
|
||||
_, err = stmt.Exec(e.Key, dataGob.Bytes())
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -121,26 +120,6 @@ func (ds *Datastore) Setup() {
|
||||
);`
|
||||
|
||||
ds.MustExec(createTableSQL)
|
||||
|
||||
if !HasPopulatedDefaults() {
|
||||
PopulateDefaults()
|
||||
}
|
||||
|
||||
if !hasPopulatedFederationDefaults() {
|
||||
if err := SetFederationGoLiveMessage(config.GetDefaults().FederationGoLiveMessage); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
if err := _datastore.SetBool("HAS_POPULATED_FEDERATION_DEFAULTS", true); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Set the server initialization date if needed.
|
||||
if hasSetInitDate, _ := GetServerInitTime(); hasSetInitDate == nil || !hasSetInitDate.Valid {
|
||||
_ = SetServerInitTime(time.Now())
|
||||
}
|
||||
|
||||
migrateDatastoreValues(_datastore)
|
||||
}
|
||||
|
||||
// Reset will delete all config entries in the datastore and start over.
|
||||
@@ -156,8 +135,6 @@ func (ds *Datastore) Reset() {
|
||||
if _, err = stmt.Exec(); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
PopulateDefaults()
|
||||
}
|
||||
|
||||
// GetDatastore returns the shared instance of the owncast datastore.
|
||||
@@ -1,54 +0,0 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/models"
|
||||
)
|
||||
|
||||
// HasPopulatedDefaults will determine if the defaults have been inserted into the database.
|
||||
func HasPopulatedDefaults() bool {
|
||||
hasPopulated, err := _datastore.GetBool("HAS_POPULATED_DEFAULTS")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return hasPopulated
|
||||
}
|
||||
|
||||
func hasPopulatedFederationDefaults() bool {
|
||||
hasPopulated, err := _datastore.GetBool("HAS_POPULATED_FEDERATION_DEFAULTS")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return hasPopulated
|
||||
}
|
||||
|
||||
// PopulateDefaults will set default values in the database.
|
||||
func PopulateDefaults() {
|
||||
_datastore.warmCache()
|
||||
|
||||
defaults := config.GetDefaults()
|
||||
|
||||
if HasPopulatedDefaults() {
|
||||
return
|
||||
}
|
||||
|
||||
_ = SetAdminPassword(defaults.AdminPassword)
|
||||
_ = SetStreamKeys(defaults.StreamKeys)
|
||||
_ = SetHTTPPortNumber(float64(defaults.WebServerPort))
|
||||
_ = SetRTMPPortNumber(float64(defaults.RTMPServerPort))
|
||||
_ = SetLogoPath(defaults.Logo)
|
||||
_ = SetServerMetadataTags([]string{"owncast", "streaming"})
|
||||
_ = SetServerSummary(defaults.Summary)
|
||||
_ = SetServerWelcomeMessage("")
|
||||
_ = SetServerName(defaults.Name)
|
||||
_ = SetExtraPageBodyContent(defaults.PageBodyContent)
|
||||
_ = SetFederationGoLiveMessage(defaults.FederationGoLiveMessage)
|
||||
_ = SetSocialHandles([]models.SocialHandle{
|
||||
{
|
||||
Platform: "github",
|
||||
URL: "https://github.com/owncast/owncast",
|
||||
},
|
||||
})
|
||||
|
||||
_ = _datastore.SetBool("HAS_POPULATED_DEFAULTS", true)
|
||||
}
|
||||
@@ -1,14 +1,5 @@
|
||||
package data
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/owncast/owncast/db"
|
||||
"github.com/owncast/owncast/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// GetMessagesCount will return the number of messages in the database.
|
||||
func GetMessagesCount() int64 {
|
||||
query := `SELECT COUNT(*) FROM messages`
|
||||
@@ -25,58 +16,3 @@ func GetMessagesCount() int64 {
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
// CreateBanIPTable will create the IP ban table if needed.
|
||||
func CreateBanIPTable(db *sql.DB) {
|
||||
createTableSQL := ` CREATE TABLE IF NOT EXISTS ip_bans (
|
||||
"ip_address" TEXT NOT NULL PRIMARY KEY,
|
||||
"notes" TEXT,
|
||||
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);`
|
||||
|
||||
stmt, err := db.Prepare(createTableSQL)
|
||||
if err != nil {
|
||||
log.Fatal("error creating ip ban table", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if _, err := stmt.Exec(); err != nil {
|
||||
log.Fatal("error creating ip ban table", err)
|
||||
}
|
||||
}
|
||||
|
||||
// BanIPAddress will persist a new IP address ban to the datastore.
|
||||
func BanIPAddress(address, note string) error {
|
||||
return _datastore.GetQueries().BanIPAddress(context.Background(), db.BanIPAddressParams{
|
||||
IpAddress: address,
|
||||
Notes: sql.NullString{String: note, Valid: true},
|
||||
})
|
||||
}
|
||||
|
||||
// IsIPAddressBanned will return if an IP address has been previously blocked.
|
||||
func IsIPAddressBanned(address string) (bool, error) {
|
||||
blocked, error := _datastore.GetQueries().IsIPAddressBlocked(context.Background(), address)
|
||||
return blocked > 0, error
|
||||
}
|
||||
|
||||
// GetIPAddressBans will return all the banned IP addresses.
|
||||
func GetIPAddressBans() ([]models.IPAddress, error) {
|
||||
result, err := _datastore.GetQueries().GetIPAddressBans(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := []models.IPAddress{}
|
||||
for _, ip := range result {
|
||||
response = append(response, models.IPAddress{
|
||||
IPAddress: ip.IpAddress,
|
||||
Notes: ip.Notes.String,
|
||||
CreatedAt: ip.CreatedAt.Time,
|
||||
})
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
// RemoveIPAddressBan will remove a previously banned IP address.
|
||||
func RemoveIPAddressBan(address string) error {
|
||||
return _datastore.GetQueries().RemoveIPAddressBan(context.Background(), address)
|
||||
}
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package data
|
||||
|
||||
import "github.com/owncast/owncast/models"
|
||||
|
||||
// GetStringSlice will return the string slice value for a key.
|
||||
func (ds *Datastore) GetStringSlice(key string) ([]string, error) {
|
||||
configEntry, err := ds.Get(key)
|
||||
if err != nil {
|
||||
return []string{}, err
|
||||
}
|
||||
return configEntry.getStringSlice()
|
||||
return configEntry.GetStringSlice()
|
||||
}
|
||||
|
||||
// SetStringSlice will set the string slice value for a key.
|
||||
func (ds *Datastore) SetStringSlice(key string, value []string) error {
|
||||
configEntry := ConfigEntry{value, key}
|
||||
configEntry := models.ConfigEntry{Value: value, Key: key}
|
||||
return ds.Save(configEntry)
|
||||
}
|
||||
|
||||
@@ -21,12 +23,12 @@ func (ds *Datastore) GetString(key string) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return configEntry.getString()
|
||||
return configEntry.GetString()
|
||||
}
|
||||
|
||||
// SetString will set the string value for a key.
|
||||
func (ds *Datastore) SetString(key string, value string) error {
|
||||
configEntry := ConfigEntry{value, key}
|
||||
configEntry := models.ConfigEntry{Value: value, Key: key}
|
||||
return ds.Save(configEntry)
|
||||
}
|
||||
|
||||
@@ -36,12 +38,12 @@ func (ds *Datastore) GetNumber(key string) (float64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return configEntry.getNumber()
|
||||
return configEntry.GetNumber()
|
||||
}
|
||||
|
||||
// SetNumber will set the numeric value for a key.
|
||||
func (ds *Datastore) SetNumber(key string, value float64) error {
|
||||
configEntry := ConfigEntry{value, key}
|
||||
configEntry := models.ConfigEntry{Value: value, Key: key}
|
||||
return ds.Save(configEntry)
|
||||
}
|
||||
|
||||
@@ -51,12 +53,12 @@ func (ds *Datastore) GetBool(key string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return configEntry.getBool()
|
||||
return configEntry.GetBool()
|
||||
}
|
||||
|
||||
// SetBool will set the boolean value for a key.
|
||||
func (ds *Datastore) SetBool(key string, value bool) error {
|
||||
configEntry := ConfigEntry{value, key}
|
||||
configEntry := models.ConfigEntry{Value: value, Key: key}
|
||||
return ds.Save(configEntry)
|
||||
}
|
||||
|
||||
@@ -66,11 +68,11 @@ func (ds *Datastore) GetStringMap(key string) (map[string]string, error) {
|
||||
if err != nil {
|
||||
return map[string]string{}, err
|
||||
}
|
||||
return configEntry.getStringMap()
|
||||
return configEntry.GetStringMap()
|
||||
}
|
||||
|
||||
// SetStringMap will set the string map value for a key.
|
||||
func (ds *Datastore) SetStringMap(key string, value map[string]string) error {
|
||||
configEntry := ConfigEntry{value, key}
|
||||
configEntry := models.ConfigEntry{Value: value, Key: key}
|
||||
return ds.Save(configEntry)
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
|
||||
"github.com/nareix/joy5/format/rtmp"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
var _hasInboundRTMPConnection = false
|
||||
@@ -33,7 +33,9 @@ func Start(setStreamAsConnected func(*io.PipeReader), setBroadcaster func(models
|
||||
_setStreamAsConnected = setStreamAsConnected
|
||||
_setBroadcaster = setBroadcaster
|
||||
|
||||
port := data.GetRTMPPortNumber()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
port := configRepository.GetRTMPPortNumber()
|
||||
s := rtmp.NewServer()
|
||||
var lis net.Listener
|
||||
var err error
|
||||
@@ -78,8 +80,10 @@ func HandleConn(c *rtmp.Conn, nc net.Conn) {
|
||||
return
|
||||
}
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
accessGranted := false
|
||||
validStreamingKeys := data.GetStreamKeys()
|
||||
validStreamingKeys := configRepository.GetStreamKeys()
|
||||
|
||||
// If a stream key override was specified then use that instead.
|
||||
if config.TemporaryStreamKey != "" {
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/services/geoip"
|
||||
)
|
||||
|
||||
@@ -48,7 +48,8 @@ func IsStreamConnected() bool {
|
||||
// Kind of a hack. It takes a handful of seconds between a RTMP connection and when HLS data is available.
|
||||
// So account for that with an artificial buffer of four segments.
|
||||
timeSinceLastConnected := time.Since(_stats.LastConnectTime.Time).Seconds()
|
||||
waitTime := math.Max(float64(data.GetStreamLatencyLevel().SecondsPerSegment)*3.0, 7)
|
||||
configRepository := configrepository.Get()
|
||||
waitTime := math.Max(float64(configRepository.GetStreamLatencyLevel().SecondsPerSegment)*3.0, 7)
|
||||
if timeSinceLastConnected < waitTime {
|
||||
return false
|
||||
}
|
||||
@@ -75,7 +76,7 @@ func SetViewerActive(viewer *models.Viewer) {
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
|
||||
// Asynchronously, optionally, fetch GeoIP data.
|
||||
// Asynchronously, optionally, fetch GeoIP configRepository.
|
||||
go func(viewer *models.Viewer) {
|
||||
viewer.Geo = _geoIPClient.GetGeoFromIP(viewer.IPAddress)
|
||||
}(viewer)
|
||||
@@ -111,27 +112,29 @@ func pruneViewerCount() {
|
||||
}
|
||||
|
||||
func saveStats() {
|
||||
if err := data.SetPeakOverallViewerCount(_stats.OverallMaxViewerCount); err != nil {
|
||||
configRepository := configrepository.Get()
|
||||
if err := configRepository.SetPeakOverallViewerCount(_stats.OverallMaxViewerCount); err != nil {
|
||||
log.Errorln("error saving viewer count", err)
|
||||
}
|
||||
if err := data.SetPeakSessionViewerCount(_stats.SessionMaxViewerCount); err != nil {
|
||||
if err := configRepository.SetPeakSessionViewerCount(_stats.SessionMaxViewerCount); err != nil {
|
||||
log.Errorln("error saving viewer count", err)
|
||||
}
|
||||
if _stats.LastDisconnectTime != nil && _stats.LastDisconnectTime.Valid {
|
||||
if err := data.SetLastDisconnectTime(_stats.LastDisconnectTime.Time); err != nil {
|
||||
if err := configRepository.SetLastDisconnectTime(_stats.LastDisconnectTime.Time); err != nil {
|
||||
log.Errorln("error saving disconnect time", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getSavedStats() models.Stats {
|
||||
savedLastDisconnectTime, _ := data.GetLastDisconnectTime()
|
||||
configRepository := configrepository.Get()
|
||||
savedLastDisconnectTime, _ := configRepository.GetLastDisconnectTime()
|
||||
|
||||
result := models.Stats{
|
||||
ChatClients: make(map[string]models.Client),
|
||||
Viewers: make(map[string]*models.Viewer),
|
||||
SessionMaxViewerCount: data.GetPeakSessionViewerCount(),
|
||||
OverallMaxViewerCount: data.GetPeakOverallViewerCount(),
|
||||
SessionMaxViewerCount: configRepository.GetPeakSessionViewerCount(),
|
||||
OverallMaxViewerCount: configRepository.GetPeakOverallViewerCount(),
|
||||
LastDisconnectTime: savedLastDisconnectTime,
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ package core
|
||||
|
||||
import (
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// GetStatus gets the status of the system.
|
||||
@@ -17,6 +17,7 @@ func GetStatus() models.Status {
|
||||
viewerCount = len(_stats.Viewers)
|
||||
}
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
return models.Status{
|
||||
Online: IsStreamConnected(),
|
||||
ViewerCount: viewerCount,
|
||||
@@ -25,7 +26,7 @@ func GetStatus() models.Status {
|
||||
LastDisconnectTime: _stats.LastDisconnectTime,
|
||||
LastConnectTime: _stats.LastConnectTime,
|
||||
VersionNumber: config.VersionNumber,
|
||||
StreamTitle: data.GetStreamTitle(),
|
||||
StreamTitle: configRepository.GetStreamTitle(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/storageproviders"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
func setupStorage() error {
|
||||
s3Config := data.GetS3Config()
|
||||
configRepository := configrepository.Get()
|
||||
s3Config := configRepository.GetS3Config()
|
||||
|
||||
if s3Config.Enabled {
|
||||
_storage = storageproviders.NewS3Storage()
|
||||
|
||||
@@ -5,9 +5,8 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
)
|
||||
|
||||
// LocalStorage represents an instance of the local storage provider for HLS video.
|
||||
@@ -22,7 +21,8 @@ func NewLocalStorage() *LocalStorage {
|
||||
|
||||
// Setup configures this storage provider.
|
||||
func (s *LocalStorage) Setup() error {
|
||||
s.host = data.GetVideoServingEndpoint()
|
||||
configRepository := configrepository.Get()
|
||||
s.host = configRepository.GetVideoServingEndpoint()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ func (s *LocalStorage) Save(filePath string, retryCount int) (string, error) {
|
||||
// Cleanup will remove old files from the storage provider.
|
||||
func (s *LocalStorage) Cleanup() error {
|
||||
// Determine how many files we should keep on disk
|
||||
maxNumber := data.GetStreamLatencyLevel().SegmentCount
|
||||
configRepository := configrepository.Get()
|
||||
maxNumber := configRepository.GetStreamLatencyLevel().SegmentCount
|
||||
buffer := 10
|
||||
return localCleanup(maxNumber + buffer)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@@ -64,9 +64,9 @@ func NewS3Storage() *S3Storage {
|
||||
// Setup sets up the s3 storage for saving the video to s3.
|
||||
func (s *S3Storage) Setup() error {
|
||||
log.Trace("Setting up S3 for external storage of video...")
|
||||
|
||||
s3Config := data.GetS3Config()
|
||||
customVideoServingEndpoint := data.GetVideoServingEndpoint()
|
||||
configRepository := configrepository.Get()
|
||||
s3Config := configRepository.GetS3Config()
|
||||
customVideoServingEndpoint := configRepository.GetVideoServingEndpoint()
|
||||
|
||||
if customVideoServingEndpoint != "" {
|
||||
s.host = customVideoServingEndpoint
|
||||
@@ -106,8 +106,9 @@ func (s *S3Storage) SegmentWritten(localFilePath string) {
|
||||
averagePerformance := utils.GetAveragePerformance(performanceMonitorKey)
|
||||
|
||||
// Warn the user about long-running save operations
|
||||
configRepository := configrepository.Get()
|
||||
if averagePerformance != 0 {
|
||||
if averagePerformance > float64(data.GetStreamLatencyLevel().SecondsPerSegment)*0.9 {
|
||||
if averagePerformance > float64(configRepository.GetStreamLatencyLevel().SecondsPerSegment)*0.9 {
|
||||
log.Warnln("Possible slow uploads: average upload S3 save duration", averagePerformance, "s. troubleshoot this issue by visiting https://owncast.online/docs/troubleshooting/")
|
||||
}
|
||||
}
|
||||
@@ -220,7 +221,8 @@ func (s *S3Storage) Cleanup() error {
|
||||
// RemoteCleanup will remove old files from the remote storage provider.
|
||||
func (s *S3Storage) RemoteCleanup() error {
|
||||
// Determine how many files we should keep on S3 storage
|
||||
maxNumber := data.GetStreamLatencyLevel().SegmentCount
|
||||
configRepository := configrepository.Get()
|
||||
maxNumber := configRepository.GetStreamLatencyLevel().SegmentCount
|
||||
buffer := 20
|
||||
|
||||
keys, err := s.getDeletableVideoSegmentsWithOffset(maxNumber + buffer)
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/owncast/owncast/core/webhooks"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/notifications"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
@@ -39,9 +40,11 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) {
|
||||
_stats.LastConnectTime = &now
|
||||
_stats.SessionMaxViewerCount = 0
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
_currentBroadcast = &models.CurrentBroadcast{
|
||||
LatencyLevel: data.GetStreamLatencyLevel(),
|
||||
OutputSettings: data.GetStreamOutputVariants(),
|
||||
LatencyLevel: configRepository.GetStreamLatencyLevel(),
|
||||
OutputSettings: configRepository.GetStreamOutputVariants(),
|
||||
}
|
||||
|
||||
StopOfflineCleanupTimer()
|
||||
@@ -69,7 +72,7 @@ func setStreamAsConnected(rtmpOut *io.PipeReader) {
|
||||
}()
|
||||
|
||||
go webhooks.SendStreamStatusEvent(models.StreamStarted)
|
||||
selectedThumbnailVideoQualityIndex, isVideoPassthrough := data.FindHighestVideoQualityIndex(_currentBroadcast.OutputSettings)
|
||||
selectedThumbnailVideoQualityIndex, isVideoPassthrough := configRepository.FindHighestVideoQualityIndex(_currentBroadcast.OutputSettings)
|
||||
transcoder.StartThumbnailGenerator(segmentPath, selectedThumbnailVideoQualityIndex, isVideoPassthrough)
|
||||
|
||||
_ = chat.SendSystemAction("Stay tuned, the stream is **starting**!", true)
|
||||
@@ -176,8 +179,9 @@ func startLiveStreamNotificationsTimer() context.CancelFunc {
|
||||
return
|
||||
}
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
// Send Fediverse message.
|
||||
if data.GetFederationEnabled() {
|
||||
if configRepository.GetFederationEnabled() {
|
||||
log.Traceln("Sending Federated Go Live message.")
|
||||
if err := activitypub.SendLive(); err != nil {
|
||||
log.Errorln(err)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
@@ -88,9 +88,9 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
if len(names) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
configRepository := configrepository.Get()
|
||||
mostRecentFile := path.Join(framePath, names[0])
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath())
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
|
||||
outputFileTemp := path.Join(config.TempDir, "tempthumbnail.jpg")
|
||||
|
||||
thumbnailCmdFlags := []string{
|
||||
@@ -120,7 +120,8 @@ func fireThumbnailGenerator(segmentPath string, variantIndex int) error {
|
||||
}
|
||||
|
||||
func makeAnimatedGifPreview(sourceFile string, outputFile string) {
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath())
|
||||
configRepository := configrepository.Get()
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
|
||||
outputFileTemp := path.Join(config.TempDir, "temppreview.gif")
|
||||
|
||||
// Filter is pulled from https://engineering.giphy.com/how-to-make-gifs-with-ffmpeg/
|
||||
|
||||
@@ -12,9 +12,9 @@ import (
|
||||
"github.com/teris-io/shortid"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/logging"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
@@ -275,15 +275,16 @@ func getVariantFromConfigQuality(quality models.StreamOutputVariant, index int)
|
||||
|
||||
// NewTranscoder will return a new Transcoder, populated by the config.
|
||||
func NewTranscoder() *Transcoder {
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(data.GetFfMpegPath())
|
||||
configRepository := configrepository.Get()
|
||||
ffmpegPath := utils.ValidatedFfmpegPath(configRepository.GetFfMpegPath())
|
||||
|
||||
transcoder := new(Transcoder)
|
||||
transcoder.ffmpegPath = ffmpegPath
|
||||
transcoder.internalListenerPort = config.InternalHLSListenerPort
|
||||
|
||||
transcoder.currentStreamOutputSettings = data.GetStreamOutputVariants()
|
||||
transcoder.currentLatencyLevel = data.GetStreamLatencyLevel()
|
||||
transcoder.codec = getCodec(data.GetVideoCodec())
|
||||
transcoder.currentStreamOutputSettings = configRepository.GetStreamOutputVariants()
|
||||
transcoder.currentLatencyLevel = configRepository.GetStreamLatencyLevel()
|
||||
transcoder.codec = getCodec(configRepository.GetVideoCodec())
|
||||
transcoder.segmentOutputPath = config.HLSStoragePath
|
||||
transcoder.playlistOutputPath = config.HLSStoragePath
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -99,9 +99,9 @@ func handleTranscoderMessage(message string) {
|
||||
func createVariantDirectories() {
|
||||
// Create private hls data dirs
|
||||
utils.CleanupDirectory(config.HLSStoragePath)
|
||||
|
||||
if len(data.GetStreamOutputVariants()) != 0 {
|
||||
for index := range data.GetStreamOutputVariants() {
|
||||
configRepository := configrepository.Get()
|
||||
if len(configRepository.GetStreamOutputVariants()) != 0 {
|
||||
for index := range configRepository.GetStreamOutputVariants() {
|
||||
if err := os.MkdirAll(path.Join(config.HLSStoragePath, strconv.Itoa(index)), 0o750); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ package webhooks
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/teris-io/shortid"
|
||||
)
|
||||
|
||||
@@ -14,13 +14,15 @@ func SendStreamStatusEvent(eventType models.EventType) {
|
||||
}
|
||||
|
||||
func sendStreamStatusEvent(eventType models.EventType, id string, timestamp time.Time) {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
SendEventToWebhooks(WebhookEvent{
|
||||
Type: eventType,
|
||||
EventData: map[string]interface{}{
|
||||
"id": id,
|
||||
"name": data.GetServerName(),
|
||||
"summary": data.GetServerSummary(),
|
||||
"streamTitle": data.GetStreamTitle(),
|
||||
"name": configRepository.GetServerName(),
|
||||
"summary": configRepository.GetServerSummary(),
|
||||
"streamTitle": configRepository.GetStreamTitle(),
|
||||
"status": getStatus(),
|
||||
"timestamp": timestamp,
|
||||
},
|
||||
|
||||
@@ -5,14 +5,16 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/chat/events"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
func TestSendStreamStatusEvent(t *testing.T) {
|
||||
data.SetServerName("my server")
|
||||
data.SetServerSummary("my server where I stream")
|
||||
data.SetStreamTitle("my stream")
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
configRepository.SetServerName("my server")
|
||||
configRepository.SetServerSummary("my server where I stream")
|
||||
configRepository.SetStreamTitle("my stream")
|
||||
|
||||
checkPayload(t, models.StreamStarted, func() {
|
||||
sendStreamStatusEvent(events.StreamStarted, "id", time.Unix(72, 6).UTC())
|
||||
|
||||
File diff suppressed because one or more lines are too long
24
go.mod
24
go.mod
@@ -7,11 +7,11 @@ toolchain go1.23.1
|
||||
require (
|
||||
github.com/CAFxX/httpcompression v0.0.9
|
||||
github.com/SherClockHolmes/webpush-go v1.3.0
|
||||
github.com/TwiN/go-away v1.6.13
|
||||
github.com/TwiN/go-away v1.6.14
|
||||
github.com/andybalholm/cascadia v1.3.2
|
||||
github.com/aws/aws-sdk-go v1.55.5
|
||||
github.com/go-chi/chi/v5 v5.1.0
|
||||
github.com/go-fed/activity v1.0.1-0.20210803212804-d866ba75dd0f
|
||||
github.com/go-fed/activity v1.0.1-0.20220119073622-b14b50eecad0
|
||||
github.com/go-fed/httpsig v1.1.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/grafov/m3u8 v0.12.0
|
||||
@@ -28,16 +28,16 @@ require (
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5
|
||||
github.com/schollz/sqlite3dump v1.3.1
|
||||
github.com/shirou/gopsutil/v4 v4.24.9
|
||||
github.com/shirou/gopsutil/v4 v4.24.10
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
|
||||
github.com/yuin/goldmark v1.7.8
|
||||
github.com/yuin/goldmark-emoji v1.0.4
|
||||
golang.org/x/crypto v0.28.0
|
||||
golang.org/x/mod v0.21.0
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/time v0.7.0
|
||||
golang.org/x/crypto v0.29.0
|
||||
golang.org/x/mod v0.22.0
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/time v0.8.0
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0
|
||||
mvdan.cc/xurls/v2 v2.5.0
|
||||
)
|
||||
@@ -49,7 +49,7 @@ require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/ebitengine/purego v0.8.0 // indirect
|
||||
github.com/ebitengine/purego v0.8.1 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-test/deep v1.0.4 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
@@ -70,9 +70,9 @@ require (
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
golang.org/x/sync v0.9.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
google.golang.org/protobuf v1.34.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
62
go.sum
62
go.sum
@@ -5,6 +5,8 @@ github.com/SherClockHolmes/webpush-go v1.3.0 h1:CAu3FvEE9QS4drc3iKNgpBWFfGqNthKl
|
||||
github.com/SherClockHolmes/webpush-go v1.3.0/go.mod h1:AxRHmJuYwKGG1PVgYzToik1lphQvDnqFYDqimHvwhIw=
|
||||
github.com/TwiN/go-away v1.6.13 h1:aB6l/FPXmA5ds+V7I9zdhxzpsLLUvVtEuS++iU/ZmgE=
|
||||
github.com/TwiN/go-away v1.6.13/go.mod h1:MpvIC9Li3minq+CGgbgUDvQ9tDaeW35k5IXZrF9MVas=
|
||||
github.com/TwiN/go-away v1.6.14 h1:gjFP+6/A36gmj0NpYX0Sz9hrdU0KtHwtNWYnsJgV4fo=
|
||||
github.com/TwiN/go-away v1.6.14/go.mod h1:d+Gv3XuqjIeFqXYuAIzlyNoDzr1vNsP5B/hRY3u/VLs=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss=
|
||||
@@ -24,8 +26,8 @@ github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhr
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/ebitengine/purego v0.8.1 h1:sdRKd6plj7KYW33EH5As6YKfe8m9zbN9JMrOjNVF/BE=
|
||||
github.com/ebitengine/purego v0.8.1/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/go-chi/chi/v5 v5.1.0 h1:acVI1TYaD+hhedDJ3r54HyA6sExp3HfXq7QWEEY/xMw=
|
||||
github.com/go-chi/chi/v5 v5.1.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5/go.mod h1:T56HUNYZUQ1AGUzhAYPugZfp36sKApVnGBgKlIY+aIE=
|
||||
@@ -80,8 +82,6 @@ github.com/lestrrat-go/strftime v1.0.4/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR7
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
|
||||
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
|
||||
@@ -111,8 +111,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI=
|
||||
github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
@@ -127,8 +125,8 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/schollz/sqlite3dump v1.3.1 h1:QXizJ7XEJ7hggjqjZ3YRtF3+javm8zKtzNByYtEkPRA=
|
||||
github.com/schollz/sqlite3dump v1.3.1/go.mod h1:mzSTjZpJH4zAb1FN3iNlhWPbbdyeBpOaTW0hukyMHyI=
|
||||
github.com/shirou/gopsutil/v4 v4.24.9 h1:KIV+/HaHD5ka5f570RZq+2SaeFsb/pq+fp2DGNWYoOI=
|
||||
github.com/shirou/gopsutil/v4 v4.24.9/go.mod h1:3fkaHNeYsUFCGZ8+9vZVWtbyM1k2eRnlL+bWO8Bxa/Q=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10 h1:7VOzPtfw/5YDU+jLEoBwXwxJbQetULywoSV4RYY7HkM=
|
||||
github.com/shirou/gopsutil/v4 v4.24.10/go.mod h1:s4D/wg+ag4rG0WO7AiTj2BeYCRhym0vM7DHbZRxnIT8=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/cobra v0.0.4-0.20190109003409-7547e83b2d85/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
@@ -145,6 +143,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
|
||||
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
@@ -156,14 +156,8 @@ github.com/valyala/gozstd v1.20.1 h1:xPnnnvjmaDDitMFfDxmQ4vpx0+3CdTg2o3lALvXTU/g
|
||||
github.com/valyala/gozstd v1.20.1/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9zoYiIPQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
|
||||
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.7 h1:5m9rrB1sW3JUMToKFQfb+FGt1U7r57IHu5GrYrG2nqU=
|
||||
github.com/yuin/goldmark v1.7.7/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
|
||||
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-emoji v1.0.3 h1:aLRkLHOuBR2czCY4R8olwMjID+tENfhyFDMCRhbIQY4=
|
||||
github.com/yuin/goldmark-emoji v1.0.3/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
|
||||
github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90=
|
||||
github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
@@ -175,14 +169,12 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
|
||||
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
|
||||
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
|
||||
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
|
||||
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
|
||||
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@@ -191,15 +183,13 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
|
||||
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
|
||||
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
|
||||
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
|
||||
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
|
||||
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180525142821-c11f84a56e43/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -214,30 +204,26 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
|
||||
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
|
||||
golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
|
||||
15
main.go
15
main.go
@@ -6,6 +6,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/owncast/owncast/logging"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
@@ -111,8 +112,10 @@ func main() {
|
||||
}
|
||||
|
||||
func handleCommandLineFlags() {
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
if *newAdminPassword != "" {
|
||||
if err := data.SetAdminPassword(*newAdminPassword); err != nil {
|
||||
if err := configRepository.SetAdminPassword(*newAdminPassword); err != nil {
|
||||
log.Errorln("Error setting your admin password.", err)
|
||||
log.Exit(1)
|
||||
} else {
|
||||
@@ -134,25 +137,25 @@ func handleCommandLineFlags() {
|
||||
}
|
||||
|
||||
log.Println("Saving new web server port number to", portNumber)
|
||||
if err := data.SetHTTPPortNumber(float64(portNumber)); err != nil {
|
||||
if err := configRepository.SetHTTPPortNumber(float64(portNumber)); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
config.WebServerPort = data.GetHTTPPortNumber()
|
||||
config.WebServerPort = configRepository.GetHTTPPortNumber()
|
||||
|
||||
// Set the web server ip
|
||||
if *webServerIPOverride != "" {
|
||||
log.Println("Saving new web server listen IP address to", *webServerIPOverride)
|
||||
if err := data.SetHTTPListenAddress(*webServerIPOverride); err != nil {
|
||||
if err := configRepository.SetHTTPListenAddress(*webServerIPOverride); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
config.WebServerIP = data.GetHTTPListenAddress()
|
||||
config.WebServerIP = configRepository.GetHTTPListenAddress()
|
||||
|
||||
// Set the rtmp server port
|
||||
if *rtmpPortOverride > 0 {
|
||||
log.Println("Saving new RTMP server port number to", *rtmpPortOverride)
|
||||
if err := data.SetRTMPPortNumber(float64(*rtmpPortOverride)); err != nil {
|
||||
if err := configRepository.SetRTMPPortNumber(float64(*rtmpPortOverride)); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"sort"
|
||||
|
||||
"github.com/owncast/owncast/core"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
@@ -68,8 +68,8 @@ func networkSpeedHealthOverviewMessage() string {
|
||||
isVideoPassthrough bool
|
||||
bitrate int
|
||||
}
|
||||
|
||||
outputVariants := data.GetStreamOutputVariants()
|
||||
configRepository := configrepository.Get()
|
||||
outputVariants := configRepository.GetStreamOutputVariants()
|
||||
|
||||
streamSortVariants := make([]singleVariant, len(outputVariants))
|
||||
for i, variant := range outputVariants {
|
||||
@@ -155,7 +155,8 @@ func wastefulBitrateOverviewMessage() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
outputVariants := data.GetStreamOutputVariants()
|
||||
configRepository := configrepository.Get()
|
||||
outputVariants := configRepository.GetStreamOutputVariants()
|
||||
|
||||
type singleVariant struct {
|
||||
isVideoPassthrough bool
|
||||
@@ -229,7 +230,8 @@ func errorCountHealthOverviewMessage() string {
|
||||
healthyPercentage := utils.IntPercentage(clientsWithErrors, totalNumberOfClients)
|
||||
|
||||
isUsingPassthrough := false
|
||||
outputVariants := data.GetStreamOutputVariants()
|
||||
configRepository := configrepository.Get()
|
||||
outputVariants := configRepository.GetStreamOutputVariants()
|
||||
for _, variant := range outputVariants {
|
||||
if variant.IsVideoPassthrough {
|
||||
isUsingPassthrough = true
|
||||
|
||||
@@ -5,8 +5,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
)
|
||||
|
||||
// How often we poll for updates.
|
||||
@@ -56,8 +56,9 @@ var _getStatus func() models.Status
|
||||
|
||||
// Start will begin the metrics collection and alerting.
|
||||
func Start(getStatus func() models.Status) {
|
||||
configRepository := configrepository.Get()
|
||||
_getStatus = getStatus
|
||||
host := data.GetServerURL()
|
||||
host := configRepository.GetServerURL()
|
||||
if host == "" {
|
||||
host = "unknown"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package data
|
||||
package models
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
@@ -12,48 +12,48 @@ type ConfigEntry struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getStringSlice() ([]string, error) {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetStringSlice() ([]string, error) {
|
||||
decoder := c.GetDecoder()
|
||||
var result []string
|
||||
err := decoder.Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getStringMap() (map[string]string, error) {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetStringMap() (map[string]string, error) {
|
||||
decoder := c.GetDecoder()
|
||||
var result map[string]string
|
||||
err := decoder.Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getString() (string, error) {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetString() (string, error) {
|
||||
decoder := c.GetDecoder()
|
||||
var result string
|
||||
err := decoder.Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getNumber() (float64, error) {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetNumber() (float64, error) {
|
||||
decoder := c.GetDecoder()
|
||||
var result float64
|
||||
err := decoder.Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getBool() (bool, error) {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetBool() (bool, error) {
|
||||
decoder := c.GetDecoder()
|
||||
var result bool
|
||||
err := decoder.Decode(&result)
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getObject(result interface{}) error {
|
||||
decoder := c.getDecoder()
|
||||
func (c *ConfigEntry) GetObject(result interface{}) error {
|
||||
decoder := c.GetDecoder()
|
||||
err := decoder.Decode(result)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ConfigEntry) getDecoder() *gob.Decoder {
|
||||
func (c *ConfigEntry) GetDecoder() *gob.Decoder {
|
||||
valueBytes := c.Value.([]byte)
|
||||
decoder := gob.NewDecoder(bytes.NewBuffer(valueBytes))
|
||||
return decoder
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/db"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/persistence/configrepository"
|
||||
"github.com/owncast/owncast/persistence/tables"
|
||||
|
||||
"github.com/owncast/owncast/notifications/browser"
|
||||
@@ -18,9 +19,10 @@ import (
|
||||
|
||||
// Notifier is an instance of the live stream notifier.
|
||||
type Notifier struct {
|
||||
datastore *data.Datastore
|
||||
browser *browser.Browser
|
||||
discord *discord.Discord
|
||||
datastore *data.Datastore
|
||||
browser *browser.Browser
|
||||
discord *discord.Discord
|
||||
configRepository configrepository.ConfigRepository
|
||||
}
|
||||
|
||||
// Setup will perform any pre-use setup for the notifier.
|
||||
@@ -30,8 +32,10 @@ func Setup(datastore *data.Datastore) {
|
||||
}
|
||||
|
||||
func initializeBrowserPushIfNeeded() {
|
||||
pubKey, _ := data.GetBrowserPushPublicKey()
|
||||
privKey, _ := data.GetBrowserPushPrivateKey()
|
||||
configRepository := configrepository.Get()
|
||||
|
||||
pubKey, _ := configRepository.GetBrowserPushPublicKey()
|
||||
privKey, _ := configRepository.GetBrowserPushPrivateKey()
|
||||
|
||||
// We need browser push keys so people can register for pushes.
|
||||
if pubKey == "" || privKey == "" {
|
||||
@@ -40,26 +44,27 @@ func initializeBrowserPushIfNeeded() {
|
||||
log.Errorln("unable to initialize browser push notification keys", err)
|
||||
}
|
||||
|
||||
if err := data.SetBrowserPushPrivateKey(browserPrivateKey); err != nil {
|
||||
if err := configRepository.SetBrowserPushPrivateKey(browserPrivateKey); err != nil {
|
||||
log.Errorln("unable to set browser push private key", err)
|
||||
}
|
||||
|
||||
if err := data.SetBrowserPushPublicKey(browserPublicKey); err != nil {
|
||||
if err := configRepository.SetBrowserPushPublicKey(browserPublicKey); err != nil {
|
||||
log.Errorln("unable to set browser push public key", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Enable browser push notifications by default.
|
||||
if !data.GetHasPerformedInitialNotificationsConfig() {
|
||||
_ = data.SetBrowserPushConfig(models.BrowserNotificationConfiguration{Enabled: true, GoLiveMessage: config.GetDefaults().FederationGoLiveMessage})
|
||||
_ = data.SetHasPerformedInitialNotificationsConfig(true)
|
||||
if !configRepository.GetHasPerformedInitialNotificationsConfig() {
|
||||
_ = configRepository.SetBrowserPushConfig(models.BrowserNotificationConfiguration{Enabled: true, GoLiveMessage: config.GetDefaults().FederationGoLiveMessage})
|
||||
_ = configRepository.SetHasPerformedInitialNotificationsConfig(true)
|
||||
}
|
||||
}
|
||||
|
||||
// New creates a new instance of the Notifier.
|
||||
func New(datastore *data.Datastore) (*Notifier, error) {
|
||||
notifier := Notifier{
|
||||
datastore: datastore,
|
||||
datastore: datastore,
|
||||
configRepository: configrepository.Get(),
|
||||
}
|
||||
|
||||
if err := notifier.setupBrowserPush(); err != nil {
|
||||
@@ -73,13 +78,13 @@ func New(datastore *data.Datastore) (*Notifier, error) {
|
||||
}
|
||||
|
||||
func (n *Notifier) setupBrowserPush() error {
|
||||
if data.GetBrowserPushConfig().Enabled {
|
||||
publicKey, err := data.GetBrowserPushPublicKey()
|
||||
if n.configRepository.GetBrowserPushConfig().Enabled {
|
||||
publicKey, err := n.configRepository.GetBrowserPushPublicKey()
|
||||
if err != nil || publicKey == "" {
|
||||
return errors.Wrap(err, "browser notifier disabled, failed to get browser push public key")
|
||||
}
|
||||
|
||||
privateKey, err := data.GetBrowserPushPrivateKey()
|
||||
privateKey, err := n.configRepository.GetBrowserPushPrivateKey()
|
||||
if err != nil || privateKey == "" {
|
||||
return errors.Wrap(err, "browser notifier disabled, failed to get browser push private key")
|
||||
}
|
||||
@@ -99,7 +104,7 @@ func (n *Notifier) notifyBrowserPush() {
|
||||
log.Errorln("error getting browser push notification destinations", err)
|
||||
}
|
||||
for _, destination := range destinations {
|
||||
unsubscribed, err := n.browser.Send(destination, data.GetServerName(), data.GetBrowserPushConfig().GoLiveMessage)
|
||||
unsubscribed, err := n.browser.Send(destination, n.configRepository.GetServerName(), n.configRepository.GetBrowserPushConfig().GoLiveMessage)
|
||||
if unsubscribed {
|
||||
// If the error is "unsubscribed", then remove the destination from the database.
|
||||
if err := RemoveNotificationForChannel(BrowserPushNotification, destination); err != nil {
|
||||
@@ -112,14 +117,14 @@ func (n *Notifier) notifyBrowserPush() {
|
||||
}
|
||||
|
||||
func (n *Notifier) setupDiscord() error {
|
||||
discordConfig := data.GetDiscordConfig()
|
||||
discordConfig := n.configRepository.GetDiscordConfig()
|
||||
if discordConfig.Enabled && discordConfig.Webhook != "" {
|
||||
var image string
|
||||
if serverURL := data.GetServerURL(); serverURL != "" {
|
||||
if serverURL := n.configRepository.GetServerURL(); serverURL != "" {
|
||||
image = serverURL + "/logo"
|
||||
}
|
||||
discordNotifier, err := discord.New(
|
||||
data.GetServerName(),
|
||||
n.configRepository.GetServerName(),
|
||||
image,
|
||||
discordConfig.Webhook,
|
||||
)
|
||||
@@ -132,12 +137,12 @@ func (n *Notifier) setupDiscord() error {
|
||||
}
|
||||
|
||||
func (n *Notifier) notifyDiscord() {
|
||||
goLiveMessage := data.GetDiscordConfig().GoLiveMessage
|
||||
streamTitle := data.GetStreamTitle()
|
||||
goLiveMessage := n.configRepository.GetDiscordConfig().GoLiveMessage
|
||||
streamTitle := n.configRepository.GetStreamTitle()
|
||||
if streamTitle != "" {
|
||||
goLiveMessage += "\n" + streamTitle
|
||||
}
|
||||
message := fmt.Sprintf("%s\n\n%s", goLiveMessage, data.GetServerURL())
|
||||
message := fmt.Sprintf("%s\n\n%s", goLiveMessage, n.configRepository.GetServerURL())
|
||||
|
||||
if err := n.discord.Send(message); err != nil {
|
||||
log.Errorln("error sending discord message", err)
|
||||
@@ -158,6 +163,7 @@ func (n *Notifier) Notify() {
|
||||
// RemoveNotificationForChannel removes a notification destination.
|
||||
func RemoveNotificationForChannel(channel, destination string) error {
|
||||
log.Debugln("Removing notification for channel", channel)
|
||||
|
||||
return data.GetDatastore().GetQueries().RemoveNotificationDestinationForChannel(context.Background(), db.RemoveNotificationDestinationForChannelParams{
|
||||
Channel: channel,
|
||||
Destination: destination,
|
||||
|
||||
@@ -2948,7 +2948,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SystemMessage'
|
||||
$ref: '#/components/schemas/MessageEvent'
|
||||
responses:
|
||||
'200':
|
||||
description: Message sent successfully
|
||||
@@ -3045,7 +3045,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserMessage'
|
||||
$ref: '#/components/schemas/MessageEvent'
|
||||
responses:
|
||||
'200':
|
||||
description: Message sent successfully
|
||||
@@ -3079,7 +3079,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SystemActionEvent'
|
||||
$ref: '#/components/schemas/MessageEvent'
|
||||
responses:
|
||||
'200':
|
||||
description: Action sent successfully
|
||||
@@ -3221,7 +3221,7 @@ paths:
|
||||
get:
|
||||
summary: Get a user's details
|
||||
operationId: GetUserDetails
|
||||
tags: ['External', 'Chat']
|
||||
tags: ['Chat']
|
||||
parameters:
|
||||
- in: path
|
||||
name: userId
|
||||
|
||||
15
persistence/authrepository/authrepository.go
Normal file
15
persistence/authrepository/authrepository.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package authrepository
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"github.com/owncast/owncast/models"
|
||||
)
|
||||
|
||||
type AuthRepository interface {
|
||||
CreateBanIPTable(db *sql.DB)
|
||||
BanIPAddress(address, note string) error
|
||||
IsIPAddressBanned(address string) (bool, error)
|
||||
GetIPAddressBans() ([]models.IPAddress, error)
|
||||
RemoveIPAddressBan(address string) error
|
||||
}
|
||||
65
persistence/authrepository/bans.go
Normal file
65
persistence/authrepository/bans.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package authrepository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"log"
|
||||
|
||||
"github.com/owncast/owncast/db"
|
||||
"github.com/owncast/owncast/models"
|
||||
)
|
||||
|
||||
// CreateBanIPTable will create the IP ban table if needed.
|
||||
func (r *SqlAuthRepository) CreateBanIPTable(db *sql.DB) {
|
||||
createTableSQL := ` CREATE TABLE IF NOT EXISTS ip_bans (
|
||||
"ip_address" TEXT NOT NULL PRIMARY KEY,
|
||||
"notes" TEXT,
|
||||
"created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);`
|
||||
|
||||
stmt, err := db.Prepare(createTableSQL)
|
||||
if err != nil {
|
||||
log.Fatal("error creating ip ban table", err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
if _, err := stmt.Exec(); err != nil {
|
||||
log.Fatal("error creating ip ban table", err)
|
||||
}
|
||||
}
|
||||
|
||||
// BanIPAddress will persist a new IP address ban to the datastore.
|
||||
func (r *SqlAuthRepository) BanIPAddress(address, note string) error {
|
||||
return r.datastore.GetQueries().BanIPAddress(context.Background(), db.BanIPAddressParams{
|
||||
IpAddress: address,
|
||||
Notes: sql.NullString{String: note, Valid: true},
|
||||
})
|
||||
}
|
||||
|
||||
// IsIPAddressBanned will return if an IP address has been previously blocked.
|
||||
func (r *SqlAuthRepository) IsIPAddressBanned(address string) (bool, error) {
|
||||
blocked, error := r.datastore.GetQueries().IsIPAddressBlocked(context.Background(), address)
|
||||
return blocked > 0, error
|
||||
}
|
||||
|
||||
// GetIPAddressBans will return all the banned IP addresses.
|
||||
func (r *SqlAuthRepository) GetIPAddressBans() ([]models.IPAddress, error) {
|
||||
result, err := r.datastore.GetQueries().GetIPAddressBans(context.Background())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := []models.IPAddress{}
|
||||
for _, ip := range result {
|
||||
response = append(response, models.IPAddress{
|
||||
IPAddress: ip.IpAddress,
|
||||
Notes: ip.Notes.String,
|
||||
CreatedAt: ip.CreatedAt.Time,
|
||||
})
|
||||
}
|
||||
return response, err
|
||||
}
|
||||
|
||||
// RemoveIPAddressBan will remove a previously banned IP address.
|
||||
func (r *SqlAuthRepository) RemoveIPAddressBan(address string) error {
|
||||
return r.datastore.GetQueries().RemoveIPAddressBan(context.Background(), address)
|
||||
}
|
||||
30
persistence/authrepository/sqlauthrepository.go
Normal file
30
persistence/authrepository/sqlauthrepository.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package authrepository
|
||||
|
||||
import (
|
||||
"github.com/owncast/owncast/core/data"
|
||||
)
|
||||
|
||||
type SqlAuthRepository struct {
|
||||
datastore *data.Datastore
|
||||
}
|
||||
|
||||
// NOTE: This is temporary during the transition period.
|
||||
var temporaryGlobalInstance AuthRepository
|
||||
|
||||
// Get will return the user repository.
|
||||
func Get() AuthRepository {
|
||||
if temporaryGlobalInstance == nil {
|
||||
i := New(data.GetDatastore())
|
||||
temporaryGlobalInstance = i
|
||||
}
|
||||
return temporaryGlobalInstance
|
||||
}
|
||||
|
||||
// New will create a new instance of the UserRepository.
|
||||
func New(datastore *data.Datastore) *SqlAuthRepository {
|
||||
r := &SqlAuthRepository{
|
||||
datastore: datastore,
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
13
persistence/configrepository/activitypub.go
Normal file
13
persistence/configrepository/activitypub.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package configrepository
|
||||
|
||||
// GetFederatedInboxMap is a mapping between account names and their outbox.
|
||||
func (r SqlConfigRepository) GetFederatedInboxMap() map[string]string {
|
||||
return map[string]string{
|
||||
r.GetDefaultFederationUsername(): r.GetDefaultFederationUsername(),
|
||||
}
|
||||
}
|
||||
|
||||
// GetDefaultFederationUsername will return the username used for sending federation activities.
|
||||
func (r *SqlConfigRepository) GetDefaultFederationUsername() string {
|
||||
return r.GetFederationUsername()
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package data
|
||||
package configrepository
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -12,8 +13,8 @@ const (
|
||||
datastoreValueVersionKey = "DATA_STORE_VERSION"
|
||||
)
|
||||
|
||||
func migrateDatastoreValues(datastore *Datastore) {
|
||||
currentVersion, _ := _datastore.GetNumber(datastoreValueVersionKey)
|
||||
func migrateDatastoreValues(datastore *data.Datastore) {
|
||||
currentVersion, _ := datastore.GetNumber(datastoreValueVersionKey)
|
||||
if currentVersion == 0 {
|
||||
currentVersion = datastoreValuesVersion
|
||||
}
|
||||
@@ -33,12 +34,12 @@ func migrateDatastoreValues(datastore *Datastore) {
|
||||
log.Fatalln("missing datastore values migration step")
|
||||
}
|
||||
}
|
||||
if err := _datastore.SetNumber(datastoreValueVersionKey, datastoreValuesVersion); err != nil {
|
||||
if err := datastore.SetNumber(datastoreValueVersionKey, datastoreValuesVersion); err != nil {
|
||||
log.Errorln("error setting datastore value version:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func migrateToDatastoreValues1(datastore *Datastore) {
|
||||
func migrateToDatastoreValues1(datastore *data.Datastore) {
|
||||
// Migrate the forbidden usernames to be a slice instead of a string.
|
||||
forbiddenUsernamesString, _ := datastore.GetString(blockedUsernamesKey)
|
||||
if forbiddenUsernamesString != "" {
|
||||
@@ -58,28 +59,32 @@ func migrateToDatastoreValues1(datastore *Datastore) {
|
||||
}
|
||||
}
|
||||
|
||||
func migrateToDatastoreValues2(datastore *Datastore) {
|
||||
func migrateToDatastoreValues2(datastore *data.Datastore) {
|
||||
configRepository := Get()
|
||||
|
||||
oldAdminPassword, _ := datastore.GetString("stream_key")
|
||||
// Avoids double hashing the password
|
||||
_ = datastore.SetString("admin_password_key", oldAdminPassword)
|
||||
_ = SetStreamKeys([]models.StreamKey{
|
||||
_ = configRepository.SetStreamKeys([]models.StreamKey{
|
||||
{Key: oldAdminPassword, Comment: "Default stream key"},
|
||||
})
|
||||
}
|
||||
|
||||
func migrateToDatastoreValues3ServingEndpoint3(_ *Datastore) {
|
||||
s3Config := GetS3Config()
|
||||
func migrateToDatastoreValues3ServingEndpoint3(_ *data.Datastore) {
|
||||
configRepository := Get()
|
||||
s3Config := configRepository.GetS3Config()
|
||||
|
||||
if !s3Config.Enabled {
|
||||
return
|
||||
}
|
||||
|
||||
_ = SetVideoServingEndpoint(s3Config.ServingEndpoint)
|
||||
_ = configRepository.SetVideoServingEndpoint(s3Config.ServingEndpoint)
|
||||
}
|
||||
|
||||
func migrateToDatastoreValues4(datastore *Datastore) {
|
||||
func migrateToDatastoreValues4(datastore *data.Datastore) {
|
||||
configRepository := Get()
|
||||
unhashed_pass, _ := datastore.GetString("admin_password_key")
|
||||
err := SetAdminPassword(unhashed_pass)
|
||||
err := configRepository.SetAdminPassword(unhashed_pass)
|
||||
if err != nil {
|
||||
log.Fatalln("error migrating admin password:", err)
|
||||
}
|
||||
62
persistence/configrepository/configkeys.go
Normal file
62
persistence/configrepository/configkeys.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package configrepository
|
||||
|
||||
const (
|
||||
extraContentKey = "extra_page_content"
|
||||
streamTitleKey = "stream_title"
|
||||
adminPasswordKey = "admin_password_key"
|
||||
logoPathKey = "logo_path"
|
||||
logoUniquenessKey = "logo_uniqueness"
|
||||
serverSummaryKey = "server_summary"
|
||||
serverWelcomeMessageKey = "server_welcome_message"
|
||||
serverNameKey = "server_name"
|
||||
serverURLKey = "server_url"
|
||||
httpPortNumberKey = "http_port_number"
|
||||
httpListenAddressKey = "http_listen_address"
|
||||
websocketHostOverrideKey = "websocket_host_override"
|
||||
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"
|
||||
s3StorageConfigKey = "s3_storage_config"
|
||||
videoLatencyLevel = "video_latency_level"
|
||||
videoStreamOutputVariantsKey = "video_stream_output_variants"
|
||||
chatDisabledKey = "chat_disabled"
|
||||
externalActionsKey = "external_actions"
|
||||
customStylesKey = "custom_styles"
|
||||
customJavascriptKey = "custom_javascript"
|
||||
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"
|
||||
chatJoinMessagesEnabledKey = "chat_join_messages_enabled"
|
||||
chatEstablishedUsersOnlyModeKey = "chat_established_users_only_mode"
|
||||
chatSpamProtectionEnabledKey = "chat_spam_protection_enabled"
|
||||
chatSlurFilterEnabledKey = "chat_slur_filter_enabled"
|
||||
notificationsEnabledKey = "notifications_enabled"
|
||||
discordConfigurationKey = "discord_configuration"
|
||||
browserPushConfigurationKey = "browser_push_configuration"
|
||||
browserPushPublicKeyKey = "browser_push_public_key"
|
||||
// nolint:gosec
|
||||
browserPushPrivateKeyKey = "browser_push_private_key"
|
||||
hasConfiguredInitialNotificationsKey = "has_configured_initial_notifications"
|
||||
hideViewerCountKey = "hide_viewer_count"
|
||||
customOfflineMessageKey = "custom_offline_message"
|
||||
customColorVariableValuesKey = "custom_color_variable_values"
|
||||
streamKeysKey = "stream_keys"
|
||||
disableSearchIndexingKey = "disable_search_indexing"
|
||||
videoServingEndpointKey = "video_serving_endpoint"
|
||||
)
|
||||
129
persistence/configrepository/configrepository.go
Normal file
129
persistence/configrepository/configrepository.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package configrepository
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
|
||||
type ConfigRepository interface {
|
||||
GetExtraPageBodyContent() string
|
||||
SetExtraPageBodyContent(content string) error
|
||||
GetStreamTitle() string
|
||||
SetStreamTitle(title string) error
|
||||
GetAdminPassword() string
|
||||
SetAdminPassword(key string) error
|
||||
GetLogoPath() string
|
||||
SetLogoPath(logo string) error
|
||||
SetLogoUniquenessString(uniqueness string) error
|
||||
GetLogoUniquenessString() string
|
||||
GetServerSummary() string
|
||||
SetServerSummary(summary string) error
|
||||
GetServerWelcomeMessage() string
|
||||
SetServerWelcomeMessage(welcomeMessage string) error
|
||||
GetServerName() string
|
||||
SetServerName(name string) error
|
||||
GetServerURL() string
|
||||
SetServerURL(url string) error
|
||||
GetHTTPPortNumber() int
|
||||
SetWebsocketOverrideHost(host string) error
|
||||
GetWebsocketOverrideHost() string
|
||||
SetHTTPPortNumber(port float64) error
|
||||
GetHTTPListenAddress() string
|
||||
SetHTTPListenAddress(address string) error
|
||||
GetRTMPPortNumber() int
|
||||
SetRTMPPortNumber(port float64) error
|
||||
GetServerMetadataTags() []string
|
||||
SetServerMetadataTags(tags []string) error
|
||||
GetDirectoryEnabled() bool
|
||||
SetDirectoryEnabled(enabled bool) error
|
||||
SetDirectoryRegistrationKey(key string) error
|
||||
GetDirectoryRegistrationKey() string
|
||||
GetSocialHandles() []models.SocialHandle
|
||||
SetSocialHandles(socialHandles []models.SocialHandle) error
|
||||
GetPeakSessionViewerCount() int
|
||||
SetPeakSessionViewerCount(count int) error
|
||||
GetPeakOverallViewerCount() int
|
||||
SetPeakOverallViewerCount(count int) error
|
||||
GetLastDisconnectTime() (*utils.NullTime, error)
|
||||
SetLastDisconnectTime(disconnectTime time.Time) error
|
||||
SetNSFW(isNSFW bool) error
|
||||
GetNSFW() bool
|
||||
SetFfmpegPath(path string) error
|
||||
GetFfMpegPath() string
|
||||
GetS3Config() models.S3
|
||||
SetS3Config(config models.S3) error
|
||||
GetStreamLatencyLevel() models.LatencyLevel
|
||||
SetStreamLatencyLevel(level float64) error
|
||||
GetStreamOutputVariants() []models.StreamOutputVariant
|
||||
SetStreamOutputVariants(variants []models.StreamOutputVariant) error
|
||||
SetChatDisabled(disabled bool) error
|
||||
GetChatDisabled() bool
|
||||
SetChatEstablishedUsersOnlyMode(enabled bool) error
|
||||
GetChatEstbalishedUsersOnlyMode() bool
|
||||
SetChatSpamProtectionEnabled(enabled bool) error
|
||||
GetChatSpamProtectionEnabled() bool
|
||||
SetChatSlurFilterEnabled(enabled bool) error
|
||||
GetChatSlurFilterEnabled() bool
|
||||
GetExternalActions() []models.ExternalAction
|
||||
SetExternalActions(actions []models.ExternalAction) error
|
||||
SetCustomStyles(styles string) error
|
||||
GetCustomStyles() string
|
||||
SetCustomJavascript(styles string) error
|
||||
GetCustomJavascript() string
|
||||
SetVideoCodec(codec string) error
|
||||
GetVideoCodec() string
|
||||
VerifySettings() error
|
||||
FindHighestVideoQualityIndex(qualities []models.StreamOutputVariant) (int, bool)
|
||||
GetForbiddenUsernameList() []string
|
||||
SetForbiddenUsernameList(usernames []string) error
|
||||
GetSuggestedUsernamesList() []string
|
||||
SetSuggestedUsernamesList(usernames []string) error
|
||||
GetServerInitTime() (*utils.NullTime, error)
|
||||
SetServerInitTime(t time.Time) error
|
||||
SetFederationEnabled(enabled bool) error
|
||||
GetFederationEnabled() bool
|
||||
SetFederationUsername(username string) error
|
||||
GetFederationUsername() string
|
||||
SetFederationGoLiveMessage(message string) error
|
||||
GetFederationGoLiveMessage() string
|
||||
SetFederationIsPrivate(isPrivate bool) error
|
||||
GetFederationIsPrivate() bool
|
||||
SetFederationShowEngagement(showEngagement bool) error
|
||||
GetFederationShowEngagement() bool
|
||||
SetBlockedFederatedDomains(domains []string) error
|
||||
GetBlockedFederatedDomains() []string
|
||||
SetChatJoinMessagesEnabled(enabled bool) error
|
||||
GetChatJoinPartMessagesEnabled() bool
|
||||
SetNotificationsEnabled(enabled bool) error
|
||||
GetNotificationsEnabled() bool
|
||||
GetDiscordConfig() models.DiscordConfiguration
|
||||
SetDiscordConfig(config models.DiscordConfiguration) error
|
||||
GetBrowserPushConfig() models.BrowserNotificationConfiguration
|
||||
SetBrowserPushConfig(config models.BrowserNotificationConfiguration) error
|
||||
SetBrowserPushPublicKey(key string) error
|
||||
GetBrowserPushPublicKey() (string, error)
|
||||
SetBrowserPushPrivateKey(key string) error
|
||||
GetBrowserPushPrivateKey() (string, error)
|
||||
SetHasPerformedInitialNotificationsConfig(hasConfigured bool) error
|
||||
GetHasPerformedInitialNotificationsConfig() bool
|
||||
GetHideViewerCount() bool
|
||||
SetHideViewerCount(hide bool) error
|
||||
GetCustomOfflineMessage() string
|
||||
SetCustomOfflineMessage(message string) error
|
||||
SetCustomColorVariableValues(variables map[string]string) error
|
||||
GetCustomColorVariableValues() map[string]string
|
||||
GetStreamKeys() []models.StreamKey
|
||||
SetStreamKeys(actions []models.StreamKey) error
|
||||
SetDisableSearchIndexing(disableSearchIndexing bool) error
|
||||
GetDisableSearchIndexing() bool
|
||||
GetVideoServingEndpoint() string
|
||||
SetVideoServingEndpoint(message string) error
|
||||
GetFederatedInboxMap() map[string]string
|
||||
GetDefaultFederationUsername() string
|
||||
GetPublicKey() string
|
||||
GetPrivateKey() string
|
||||
SetPublicKey(key string) error
|
||||
SetPrivateKey(key string) error
|
||||
}
|
||||
23
persistence/configrepository/crypto.go
Normal file
23
persistence/configrepository/crypto.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package configrepository
|
||||
|
||||
// GetPublicKey will return the public key.
|
||||
func (r *SqlConfigRepository) GetPublicKey() string {
|
||||
value, _ := r.datastore.GetString(publicKeyKey)
|
||||
return value
|
||||
}
|
||||
|
||||
// SetPublicKey will save the public key.
|
||||
func (r *SqlConfigRepository) SetPublicKey(key string) error {
|
||||
return r.datastore.SetString(publicKeyKey, key)
|
||||
}
|
||||
|
||||
// GetPrivateKey will return the private key.
|
||||
func (r *SqlConfigRepository) GetPrivateKey() string {
|
||||
value, _ := r.datastore.GetString(privateKeyKey)
|
||||
return value
|
||||
}
|
||||
|
||||
// SetPrivateKey will save the private key.
|
||||
func (r *SqlConfigRepository) SetPrivateKey(key string) error {
|
||||
return r.datastore.SetString(privateKeyKey, key)
|
||||
}
|
||||
62
persistence/configrepository/defaults.go
Normal file
62
persistence/configrepository/defaults.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package configrepository
|
||||
|
||||
import (
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PopulateDefaults will set default values in the database.
|
||||
func (r *SqlConfigRepository) PopulateDefaults() {
|
||||
key := "HAS_POPULATED_DEFAULTS"
|
||||
|
||||
r.datastore.WarmCache()
|
||||
|
||||
defaults := config.GetDefaults()
|
||||
|
||||
_ = r.SetAdminPassword(defaults.AdminPassword)
|
||||
_ = r.SetStreamKeys(defaults.StreamKeys)
|
||||
_ = r.SetHTTPPortNumber(float64(defaults.WebServerPort))
|
||||
_ = r.SetRTMPPortNumber(float64(defaults.RTMPServerPort))
|
||||
_ = r.SetLogoPath(defaults.Logo)
|
||||
_ = r.SetServerMetadataTags([]string{"owncast", "streaming"})
|
||||
_ = r.SetServerSummary(defaults.Summary)
|
||||
_ = r.SetServerWelcomeMessage("")
|
||||
_ = r.SetServerName(defaults.Name)
|
||||
_ = r.SetExtraPageBodyContent(defaults.PageBodyContent)
|
||||
_ = r.SetFederationGoLiveMessage(defaults.FederationGoLiveMessage)
|
||||
_ = r.SetSocialHandles([]models.SocialHandle{
|
||||
{
|
||||
Platform: "github",
|
||||
URL: "https://github.com/owncast/owncast",
|
||||
},
|
||||
})
|
||||
|
||||
if !r.HasPopulatedFederationDefaults() {
|
||||
if err := r.SetFederationGoLiveMessage(config.GetDefaults().FederationGoLiveMessage); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
if err := r.datastore.SetBool("HAS_POPULATED_FEDERATION_DEFAULTS", true); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
_ = r.datastore.SetBool(key, true)
|
||||
}
|
||||
|
||||
// HasPopulatedDefaults will determine if the defaults have been inserted into the database.
|
||||
func (r *SqlConfigRepository) HasPopulatedDefaults() bool {
|
||||
hasPopulated, err := r.datastore.GetBool("HAS_POPULATED_DEFAULTS")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return hasPopulated
|
||||
}
|
||||
|
||||
func (r *SqlConfigRepository) HasPopulatedFederationDefaults() bool {
|
||||
hasPopulated, err := r.datastore.GetBool("HAS_POPULATED_FEDERATION_DEFAULTS")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return hasPopulated
|
||||
}
|
||||
1003
persistence/configrepository/sqlconfigrepository.go
Normal file
1003
persistence/configrepository/sqlconfigrepository.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
"config:recommended"
|
||||
],
|
||||
"baseBranches": [
|
||||
"develop"
|
||||
@@ -12,7 +12,7 @@
|
||||
"platformAutomerge": true
|
||||
},
|
||||
"npm": {
|
||||
"stabilityDays": 3
|
||||
"minimumReleaseAge": "3 days"
|
||||
},
|
||||
"dependencyDashboard": true,
|
||||
"major": {
|
||||
@@ -38,13 +38,6 @@
|
||||
"platformAutomerge": true,
|
||||
"dependencyDashboardApproval": false
|
||||
},
|
||||
{
|
||||
"description": "Require approval for every Go language update",
|
||||
"dependencyDashboardApproval": true,
|
||||
"matchPackagePatterns": [
|
||||
"go"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "Ignore the old pre-0.1.0 web packages",
|
||||
"matchPackageNames": [
|
||||
@@ -56,9 +49,21 @@
|
||||
"postcss-cli",
|
||||
"@videojs/themes",
|
||||
"@joeattardi/emoji-button",
|
||||
"preact"
|
||||
"preact",
|
||||
"github.com/go-fed/activity",
|
||||
"go"
|
||||
],
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"description": "Do not auto-merge statically assigned versions in npm",
|
||||
"matchManagers": [
|
||||
"npm"
|
||||
],
|
||||
"matchCurrentVersion": "/^[0-9]+\\.[0-9]+\\.[0-9]+$/",
|
||||
"automerge": false,
|
||||
"platformAutomerge": false,
|
||||
"dependencyDashboardApproval": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
2
static/web/404.html
vendored
2
static/web/404.html
vendored
File diff suppressed because one or more lines are too long
2
static/web/404/index.html
vendored
2
static/web/404/index.html
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/00768e8d.992d423f0c9ceea4.js
vendored
Normal file
1
static/web/_next/static/chunks/00768e8d.992d423f0c9ceea4.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1913-67d64a9d283405ec.js
vendored
Normal file
1
static/web/_next/static/chunks/1913-67d64a9d283405ec.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1913],{55945:function(t,n,e){e.d(n,{u:function(){return r}});function r(t){return n=>{let e=(t?Math[t]:Math.trunc)(n);return 0===e?0:e}}},98172:function(t,n,e){e.d(n,{U:function(){return u}});var r=e(46042);function u(t,n){let e=+(0,r.Q)(t)-+(0,r.Q)(n);return e<0?-1:e>0?1:e}},64077:function(t,n,e){e.d(n,{_:function(){return u}});var r=e(46042);function u(t,n){return+(0,r.Q)(t)-+(0,r.Q)(n)}},4349:function(t,n,e){e.d(n,{d:function(){return o}});var r=e(29675),u=e(98172),i=e(46042);function o(t,n,e){let[o,a,f]=(0,r.d)(null==e?void 0:e.in,t,t,n),s=(0,u.U)(a,f),l=Math.abs(function(t,n,e){let[u,i]=(0,r.d)(void 0,t,n);return 12*(u.getFullYear()-i.getFullYear())+(u.getMonth()-i.getMonth())}(a,f));if(l<1)return 0;1===a.getMonth()&&a.getDate()>27&&a.setDate(30),a.setMonth(a.getMonth()-s*l);let c=(0,u.U)(a,f)===-s;(function(t,n){let e=(0,i.Q)(t,void 0);return+function(t,n){let e=(0,i.Q)(t,null==n?void 0:n.in);return e.setHours(23,59,59,999),e}(e,void 0)==+function(t,n){let e=(0,i.Q)(t,null==n?void 0:n.in),r=e.getMonth();return e.setFullYear(e.getFullYear(),r+1,0),e.setHours(23,59,59,999),e}(e,void 0)})(o)&&1===l&&1===(0,u.U)(o,f)&&(c=!1);let d=s*(l-+c);return 0===d?0:d}},94817:function(t,n,e){e.d(n,{c:function(){return i}});var r=e(55945),u=e(64077);function i(t,n,e){let i=(0,u._)(t,n)/1e3;return(0,r.u)(null==e?void 0:e.roundingMethod)(i)}},61913:function(t,n,e){e.d(n,{Q:function(){return d}});var r=e(16393),u=e(71397),i=e(45662),o=e(98422),a=e(29675),f=e(98172),s=e(96707),l=e(4349),c=e(94817);function d(t,n){return function(t,n,e){var r,d;let h;let D=(0,i.j)(),M=null!==(d=null!==(r=null==e?void 0:e.locale)&&void 0!==r?r:D.locale)&&void 0!==d?d:u._,v=(0,f.U)(t,n);if(isNaN(v))throw RangeError("Invalid time value");let m=Object.assign({},e,{addSuffix:null==e?void 0:e.addSuffix,comparison:v}),[g,X]=(0,a.d)(null==e?void 0:e.in,...v>0?[n,t]:[t,n]),H=(0,c.c)(X,g),_=Math.round((H-((0,o.D)(X)-(0,o.D)(g))/1e3)/60);if(_<2){if(null==e?void 0:e.includeSeconds){if(H<5)return M.formatDistance("lessThanXSeconds",5,m);if(H<10)return M.formatDistance("lessThanXSeconds",10,m);if(H<20)return M.formatDistance("lessThanXSeconds",20,m);if(H<40)return M.formatDistance("halfAMinute",0,m);else if(H<60)return M.formatDistance("lessThanXMinutes",1,m);else return M.formatDistance("xMinutes",1,m)}return 0===_?M.formatDistance("lessThanXMinutes",1,m):M.formatDistance("xMinutes",_,m)}if(_<45)return M.formatDistance("xMinutes",_,m);if(_<90)return M.formatDistance("aboutXHours",1,m);if(_<s.H_)return M.formatDistance("aboutXHours",Math.round(_/60),m);if(_<2520)return M.formatDistance("xDays",1,m);if(_<s.fH){let t=Math.round(_/s.H_);return M.formatDistance("xDays",t,m)}if(_<2*s.fH)return h=Math.round(_/s.fH),M.formatDistance("aboutXMonths",h,m);if((h=(0,l.d)(X,g))<12){let t=Math.round(_/s.fH);return M.formatDistance("xMonths",t,m)}{let t=h%12,n=Math.trunc(h/12);return t<3?M.formatDistance("aboutXYears",n,m):t<9?M.formatDistance("overXYears",n,m):M.formatDistance("almostXYears",n+1,m)}}(t,(0,r.L)(t,Date.now()),n)}}}]);
|
||||
1
static/web/_next/static/chunks/2154-487cb534e26c89a5.js
vendored
Normal file
1
static/web/_next/static/chunks/2154-487cb534e26c89a5.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/2306.e3ecc3934cd527cd.js
vendored
Normal file
1
static/web/_next/static/chunks/2306.e3ecc3934cd527cd.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/2642-f5c921701afa9b18.js
vendored
Normal file
1
static/web/_next/static/chunks/2642-f5c921701afa9b18.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3883],{23883:function(e,t,n){function r(e){for(var t={},n=e.split(" "),r=0;r<n.length;++r)t[n[r]]=!0;return t}n.r(t),n.d(t,{groovy:function(){return y}});var i,a=r("abstract as assert boolean break byte case catch char class const continue def default do double else enum extends final finally float for goto if implements import in instanceof int interface long native new package private protected public return short static strictfp super switch synchronized threadsafe throw throws trait transient try void volatile while"),o=r("catch class def do else enum finally for if interface switch trait try while"),l=r("return break continue"),s=r("null true false this");function u(e,t){var n=e.next();if('"'==n||"'"==n)return f(n,e,t);if(/[\[\]{}\(\),;\:\.]/.test(n))return i=n,null;if(/\d/.test(n))return e.eatWhile(/[\w\.]/),e.eat(/eE/)&&(e.eat(/\+\-/),e.eatWhile(/\d/)),"number";if("/"==n){if(e.eat("*"))return t.tokenize.push(p),p(e,t);if(e.eat("/"))return e.skipToEnd(),"comment";if(k(t.lastToken,!1))return f(n,e,t)}if("-"==n&&e.eat(">"))return i="->",null;if(/[+\-*&%=<>!?|\/~]/.test(n))return e.eatWhile(/[+\-*&%=<>|~]/),"operator";if(e.eatWhile(/[\w\$_]/),"@"==n)return e.eatWhile(/[\w\$_\.]/),"meta";if("."==t.lastToken)return"property";if(e.eat(":"))return i="proplabel","property";var r=e.current();return s.propertyIsEnumerable(r)?"atom":a.propertyIsEnumerable(r)?(o.propertyIsEnumerable(r)?i="newstatement":l.propertyIsEnumerable(r)&&(i="standalone"),"keyword"):"variable"}function f(e,t,n){var r=!1;if("/"!=e&&t.eat(e)){if(!t.eat(e))return"string";r=!0}function i(t,n){for(var i,a=!1,o=!r;null!=(i=t.next());){if(i==e&&!a){if(!r)break;if(t.match(e+e)){o=!0;break}}if('"'==e&&"$"==i&&!a){if(t.eat("{"))return n.tokenize.push(function(){var e=1;function t(t,n){if("}"==t.peek()){if(0==--e)return n.tokenize.pop(),n.tokenize[n.tokenize.length-1](t,n)}else"{"==t.peek()&&e++;return u(t,n)}return t.isBase=!0,t}()),"string";if(t.match(/^\w/,!1))return n.tokenize.push(c),"string"}a=!a&&"\\"==i}return o&&n.tokenize.pop(),"string"}return n.tokenize.push(i),i(t,n)}function c(e,t){var n=e.match(/^(\.|[\w\$_]+)/);return n?"."==n[0]?null:"variable":(t.tokenize.pop(),t.tokenize[t.tokenize.length-1](e,t))}function p(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize.pop();break}r="*"==n}return"comment"}function k(e,t){return!e||"operator"==e||"->"==e||/[\.\[\{\(,;:]/.test(e)||"newstatement"==e||"keyword"==e||"proplabel"==e||"standalone"==e&&!t}function m(e,t,n,r,i){this.indented=e,this.column=t,this.type=n,this.align=r,this.prev=i}function h(e,t,n){return e.context=new m(e.indented,t,n,null,e.context)}function d(e){var t=e.context.type;return(")"==t||"]"==t||"}"==t)&&(e.indented=e.context.indented),e.context=e.context.prev}u.isBase=!0;let y={name:"groovy",startState:function(e){return{tokenize:[u],context:new m(-e,0,"top",!1),indented:0,startOfLine:!0,lastToken:null}},token:function(e,t){var n=t.context;if(e.sol()&&(null==n.align&&(n.align=!1),t.indented=e.indentation(),t.startOfLine=!0,"statement"!=n.type||k(t.lastToken,!0)||(d(t),n=t.context)),e.eatSpace())return null;i=null;var r=t.tokenize[t.tokenize.length-1](e,t);if("comment"==r)return r;if(null==n.align&&(n.align=!0),(";"==i||":"==i)&&"statement"==n.type)d(t);else if("->"==i&&"statement"==n.type&&"}"==n.prev.type)d(t),t.context.align=!1;else if("{"==i)h(t,e.column(),"}");else if("["==i)h(t,e.column(),"]");else if("("==i)h(t,e.column(),")");else if("}"==i){for(;"statement"==n.type;)n=d(t);for("}"==n.type&&(n=d(t));"statement"==n.type;)n=d(t)}else i==n.type?d(t):("}"==n.type||"top"==n.type||"statement"==n.type&&"newstatement"==i)&&h(t,e.column(),"statement");return t.startOfLine=!1,t.lastToken=i||r,r},indent:function(e,t,n){if(!e.tokenize[e.tokenize.length-1].isBase)return null;var r=t&&t.charAt(0),i=e.context;"statement"!=i.type||k(e.lastToken,!0)||(i=i.prev);var a=r==i.type;return"statement"==i.type?i.indented+("{"==r?0:n.unit):i.align?i.column+(a?0:1):i.indented+(a?0:n.unit)},languageData:{indentOnInput:/^\s*[{}]$/,commentTokens:{line:"//",block:{open:"/*",close:"*/"}},closeBrackets:{brackets:["(","[","{","'",'"',"'''",'"""']}}}}}]);
|
||||
1
static/web/_next/static/chunks/3883.915954d7c9022abf.js
vendored
Normal file
1
static/web/_next/static/chunks/3883.915954d7c9022abf.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3883],{23883:function(e,t,n){function r(e){for(var t={},n=e.split(" "),r=0;r<n.length;++r)t[n[r]]=!0;return t}n.r(t),n.d(t,{groovy:function(){return y}});var i,a=r("abstract as assert boolean break byte case catch char class const continue def default do double else enum extends final finally float for goto if implements import in instanceof int interface long native new package private protected public return short static strictfp super switch synchronized threadsafe throw throws trait transient try void volatile while"),o=r("catch class def do else enum finally for if interface switch trait try while"),l=r("return break continue"),s=r("null true false this");function u(e,t){var n=e.next();if('"'==n||"'"==n)return c(n,e,t);if(/[\[\]{}\(\),;\:\.]/.test(n))return i=n,null;if(/\d/.test(n))return e.eatWhile(/[\w\.]/),e.eat(/eE/)&&(e.eat(/\+\-/),e.eatWhile(/\d/)),"number";if("/"==n){if(e.eat("*"))return t.tokenize.push(p),p(e,t);if(e.eat("/"))return e.skipToEnd(),"comment";if(k(t.lastToken,!1))return c(n,e,t)}if("-"==n&&e.eat(">"))return i="->",null;if(/[+\-*&%=<>!?|\/~]/.test(n))return e.eatWhile(/[+\-*&%=<>|~]/),"operator";if(e.eatWhile(/[\w\$_]/),"@"==n)return e.eatWhile(/[\w\$_\.]/),"meta";if("."==t.lastToken)return"property";if(e.eat(":"))return i="proplabel","property";var r=e.current();return s.propertyIsEnumerable(r)?"atom":a.propertyIsEnumerable(r)?(o.propertyIsEnumerable(r)?i="newstatement":l.propertyIsEnumerable(r)&&(i="standalone"),"keyword"):"variable"}function c(e,t,n){var r=!1;if("/"!=e&&t.eat(e)){if(!t.eat(e))return"string";r=!0}function i(t,n){for(var i,a=!1,o=!r;null!=(i=t.next());){if(i==e&&!a){if(!r)break;if(t.match(e+e)){o=!0;break}}if('"'==e&&"$"==i&&!a){if(t.eat("{"))return n.tokenize.push(function(){var e=1;function t(t,n){if("}"==t.peek()){if(0==--e)return n.tokenize.pop(),n.tokenize[n.tokenize.length-1](t,n)}else"{"==t.peek()&&e++;return u(t,n)}return t.isBase=!0,t}()),"string";if(t.match(/^\w/,!1))return n.tokenize.push(f),"string"}a=!a&&"\\"==i}return o&&n.tokenize.pop(),"string"}return n.tokenize.push(i),i(t,n)}function f(e,t){var n=e.match(/^(\.|[\w\$_]+)/);return(n&&e.match("."==n[0]?/^[\w$_]/:/^\./)||t.tokenize.pop(),n)?"."==n[0]?null:"variable":t.tokenize[t.tokenize.length-1](e,t)}function p(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize.pop();break}r="*"==n}return"comment"}function k(e,t){return!e||"operator"==e||"->"==e||/[\.\[\{\(,;:]/.test(e)||"newstatement"==e||"keyword"==e||"proplabel"==e||"standalone"==e&&!t}function m(e,t,n,r,i){this.indented=e,this.column=t,this.type=n,this.align=r,this.prev=i}function h(e,t,n){return e.context=new m(e.indented,t,n,null,e.context)}function d(e){var t=e.context.type;return(")"==t||"]"==t||"}"==t)&&(e.indented=e.context.indented),e.context=e.context.prev}u.isBase=!0;let y={name:"groovy",startState:function(e){return{tokenize:[u],context:new m(-e,0,"top",!1),indented:0,startOfLine:!0,lastToken:null}},token:function(e,t){var n=t.context;if(e.sol()&&(null==n.align&&(n.align=!1),t.indented=e.indentation(),t.startOfLine=!0,"statement"!=n.type||k(t.lastToken,!0)||(d(t),n=t.context)),e.eatSpace())return null;i=null;var r=t.tokenize[t.tokenize.length-1](e,t);if("comment"==r)return r;if(null==n.align&&(n.align=!0),(";"==i||":"==i)&&"statement"==n.type)d(t);else if("->"==i&&"statement"==n.type&&"}"==n.prev.type)d(t),t.context.align=!1;else if("{"==i)h(t,e.column(),"}");else if("["==i)h(t,e.column(),"]");else if("("==i)h(t,e.column(),")");else if("}"==i){for(;"statement"==n.type;)n=d(t);for("}"==n.type&&(n=d(t));"statement"==n.type;)n=d(t)}else i==n.type?d(t):("}"==n.type||"top"==n.type||"statement"==n.type&&"newstatement"==i)&&h(t,e.column(),"statement");return t.startOfLine=!1,t.lastToken=i||r,r},indent:function(e,t,n){if(!e.tokenize[e.tokenize.length-1].isBase)return null;var r=t&&t.charAt(0),i=e.context;"statement"!=i.type||k(e.lastToken,!0)||(i=i.prev);var a=r==i.type;return"statement"==i.type?i.indented+("{"==r?0:n.unit):i.align?i.column+(a?0:1):i.indented+(a?0:n.unit)},languageData:{indentOnInput:/^\s*[{}]$/,commentTokens:{line:"//",block:{open:"/*",close:"*/"}},closeBrackets:{brackets:["(","[","{","'",'"',"'''",'"""']}}}}}]);
|
||||
1
static/web/_next/static/chunks/4009-77394d6a9f47e0fa.js
vendored
Normal file
1
static/web/_next/static/chunks/4009-77394d6a9f47e0fa.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/4065-e951dd28c6b5f4c7.js
vendored
Normal file
1
static/web/_next/static/chunks/4065-e951dd28c6b5f4c7.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/5308-462ef190e34398d2.js
vendored
Normal file
1
static/web/_next/static/chunks/5308-462ef190e34398d2.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/561-a7d91d9109b7c25f.js
vendored
Normal file
1
static/web/_next/static/chunks/561-a7d91d9109b7c25f.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[6166],{1554:function(t,n,e){e.d(n,{u:function(){return r}});function r(t){return n=>{let e=(t?Math[t]:Math.trunc)(n);return 0===e?0:e}}},67364:function(t,n,e){e.d(n,{U:function(){return u}});var r=e(63923);function u(t,n){let e=(0,r.Q)(t),u=(0,r.Q)(n),a=e.getTime()-u.getTime();return a<0?-1:a>0?1:a}},58005:function(t,n,e){e.d(n,{_:function(){return u}});var r=e(63923);function u(t,n){return+(0,r.Q)(t)-+(0,r.Q)(n)}},76732:function(t,n,e){e.d(n,{d:function(){return a}});var r=e(67364),u=e(63923);function a(t,n){let e;let a=(0,u.Q)(t),o=(0,u.Q)(n),i=(0,r.U)(a,o),f=Math.abs(function(t,n){let e=(0,u.Q)(t),r=(0,u.Q)(n);return 12*(e.getFullYear()-r.getFullYear())+(e.getMonth()-r.getMonth())}(a,o));if(f<1)e=0;else{1===a.getMonth()&&a.getDate()>27&&a.setDate(30),a.setMonth(a.getMonth()-i*f);let n=(0,r.U)(a,o)===-i;(function(t){let n=(0,u.Q)(t);return+function(t){let n=(0,u.Q)(t);return n.setHours(23,59,59,999),n}(n)==+function(t){let n=(0,u.Q)(t),e=n.getMonth();return n.setFullYear(n.getFullYear(),e+1,0),n.setHours(23,59,59,999),n}(n)})((0,u.Q)(t))&&1===f&&1===(0,r.U)(t,o)&&(n=!1),e=i*(f-Number(n))}return 0===e?0:e}},65476:function(t,n,e){e.d(n,{c:function(){return a}});var r=e(1554),u=e(58005);function a(t,n,e){let a=(0,u._)(t,n)/1e3;return(0,r.u)(null==e?void 0:e.roundingMethod)(a)}},46166:function(t,n,e){e.d(n,{Q:function(){return d}});var r=e(75696),u=e(67364),a=e(69005),o=e(76732),i=e(65476),f=e(63923),s=e(5360),c=e(67751),l=e(17956);function d(t,n){return function(t,n,e){var r,d;let h,D,m;let M=(0,c.j)(),Q=null!==(d=null!==(r=null==e?void 0:e.locale)&&void 0!==r?r:M.locale)&&void 0!==d?d:s._,v=(0,u.U)(t,n);if(isNaN(v))throw RangeError("Invalid time value");let g=Object.assign({},e,{addSuffix:null==e?void 0:e.addSuffix,comparison:v});v>0?(h=(0,f.Q)(n),D=(0,f.Q)(t)):(h=(0,f.Q)(t),D=(0,f.Q)(n));let X=(0,i.c)(D,h),H=Math.round((X-((0,l.D)(D)-(0,l.D)(h))/1e3)/60);if(H<2){if(null==e?void 0:e.includeSeconds){if(X<5)return Q.formatDistance("lessThanXSeconds",5,g);if(X<10)return Q.formatDistance("lessThanXSeconds",10,g);if(X<20)return Q.formatDistance("lessThanXSeconds",20,g);if(X<40)return Q.formatDistance("halfAMinute",0,g);else if(X<60)return Q.formatDistance("lessThanXMinutes",1,g);else return Q.formatDistance("xMinutes",1,g)}return 0===H?Q.formatDistance("lessThanXMinutes",1,g):Q.formatDistance("xMinutes",H,g)}if(H<45)return Q.formatDistance("xMinutes",H,g);if(H<90)return Q.formatDistance("aboutXHours",1,g);if(H<a.H_)return Q.formatDistance("aboutXHours",Math.round(H/60),g);if(H<2520)return Q.formatDistance("xDays",1,g);if(H<a.fH){let t=Math.round(H/a.H_);return Q.formatDistance("xDays",t,g)}if(H<2*a.fH)return m=Math.round(H/a.fH),Q.formatDistance("aboutXMonths",m,g);if((m=(0,o.d)(D,h))<12){let t=Math.round(H/a.fH);return Q.formatDistance("xMonths",t,g)}{let t=m%12,n=Math.trunc(m/12);return t<3?Q.formatDistance("aboutXYears",n,g):t<9?Q.formatDistance("overXYears",n,g):Q.formatDistance("almostXYears",n+1,g)}}(t,(0,r.L)(t,Date.now()),n)}}}]);
|
||||
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/6864.8fedf6154a7f8faf.js
vendored
Normal file
1
static/web/_next/static/chunks/6864.8fedf6154a7f8faf.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user