0

Merge remote-tracking branch 'origin/develop' into webv2

This commit is contained in:
Gabe Kangas 2022-06-19 13:52:22 -07:00
commit 6b22be8cf3
No known key found for this signature in database
GPG Key ID: 9A56337728BC81EA
60 changed files with 1533 additions and 1154 deletions

View File

@ -2,7 +2,7 @@
root = true
[*]
indent_style = space
indent_style = tab
indent_size = 2
tab_width = 2
end_of_line = lf

View File

@ -0,0 +1,40 @@
# See https://docs.earthly.dev/ci-integration/vendor-specific-guides/gh-actions-integration
# for details.
name: Build nightly docker
on:
workflow_dispatch:
schedule:
- cron: '0 2 * * *'
jobs:
Docker:
runs-on: ubuntu-latest
steps:
- uses: earthly/actions-setup@v1
with:
version: 'latest' # or pin to an specific version, e.g. "v0.6.10"
- name: Earthly version
run: earthly --version
- name: Log into GitHub Container Registry
env:
GH_CR_PAT: ${{ secrets.GH_CR_PAT }}
run: echo "${{ secrets.GH_CR_PAT }}" | docker login https://ghcr.io -u ${{ github.actor }} --password-stdin
if: env.GH_CR_PAT != null
- name: Set up QEMU
id: qemu
uses: docker/setup-qemu-action@v1
with:
image: tonistiigi/binfmt:latest
platforms: all
- uses: actions/checkout@v3
- name: Checkout and build
if: env.GH_CR_PAT != null
env:
GH_CR_PAT: ${{ secrets.GH_CR_PAT }}
run: cd build/release && ./docker-nightly-earthly.sh

129
Earthfile Normal file
View File

@ -0,0 +1,129 @@
VERSION --new-platform 0.6
FROM --platform=linux/amd64 alpine:latest
ARG version=develop
WORKDIR /build
build-all:
BUILD --platform=linux/amd64 --platform=linux/386 --platform=linux/arm64 --platform=linux/arm/v7 --platform=darwin/amd64 +build
package-all:
BUILD --platform=linux/amd64 --platform=linux/386 --platform=linux/arm64 --platform=linux/arm/v7 --platform=darwin/amd64 +package
docker-all:
BUILD --platform=linux/amd64 --platform=linux/386 --platform=linux/arm64 --platform=linux/arm/v7 +docker
crosscompiler:
# This image is missing a few platforms, so we'll add them locally
FROM --platform=linux/amd64 bdwyertech/go-crosscompile
RUN curl -sfL "https://musl.cc/armv7l-linux-musleabihf-cross.tgz" | tar zxf - -C /usr/ --strip-components=1
RUN curl -sfL "https://musl.cc/i686-linux-musl-cross.tgz" | tar zxf - -C /usr/ --strip-components=1
RUN curl -sfL "https://musl.cc/x86_64-linux-musl-cross.tgz" | tar zxf - -C /usr/ --strip-components=1
code:
FROM --platform=linux/amd64 +crosscompiler
COPY . /build
# GIT CLONE --branch=$version git@github.com:owncast/owncast.git /build
build:
ARG EARTHLY_GIT_HASH # provided by Earthly
ARG TARGETPLATFORM # provided by Earthly
ARG TARGETOS # provided by Earthly
ARG TARGETARCH # provided by Earthly
ARG GOOS=$TARGETOS
ARG GOARCH=$TARGETARCH
FROM --platform=linux/amd64 +code
RUN echo $EARTHLY_GIT_HASH
RUN echo "Finding CC configuration for $TARGETPLATFORM"
IF [ "$TARGETPLATFORM" = "linux/amd64" ]
ARG NAME=linux-64bit
ARG CC=x86_64-linux-musl-gcc
ARG CXX=x86_64-linux-musl-g++
ELSE IF [ "$TARGETPLATFORM" = "linux/386" ]
ARG NAME=linux-32bit
ARG CC=i686-linux-musl-gcc
ARG CXX=i686-linux-musl-g++
ELSE IF [ "$TARGETPLATFORM" = "linux/arm64" ]
ARG NAME=linux-arm64
ARG CC=aarch64-linux-musl-gcc
ARG CXX=aarch64-linux-musl-g++
ELSE IF [ "$TARGETPLATFORM" = "linux/arm/v7" ]
ARG NAME=linux-arm7
ARG CC=armv7l-linux-musleabihf-gcc
ARG CXX=armv7l-linux-musleabihf-g++
ARG GOARM=7
ELSE IF [ "$TARGETPLATFORM" = "darwin/amd64" ]
ARG NAME=macOS-64bit
ARG CC=o64-clang
ARG CXX=o64-clang++
ELSE
RUN echo "Failed to find CC configuration for $TARGETPLATFORM"
ARG --required CC
ARG --required CXX
END
ENV CGO_ENABLED=1
ENV GOOS=$GOOS
ENV GOARCH=$GOARCH
ENV GOARM=$GOARM
ENV CC=$CC
ENV CXX=$CXX
WORKDIR /build
# MacOSX disallows static executables, so we omit the static flag on this platform
RUN go build -a -installsuffix cgo -ldflags "$([ "$GOOS"z != darwinz ] && echo "-linkmode external -extldflags -static ") -s -w -X github.com/owncast/owncast/config.GitCommit=$EARTHLY_GIT_HASH -X github.com/owncast/owncast/config.VersionNumber=$version -X github.com/owncast/owncast/config.BuildPlatform=$NAME" -o owncast main.go
COPY +tailwind/prod-tailwind.min.css /build/dist/webroot/js/web_modules/tailwindcss/dist/tailwind.min.css
SAVE ARTIFACT owncast owncast
SAVE ARTIFACT webroot webroot
SAVE ARTIFACT README.md README.md
tailwind:
FROM +code
WORKDIR /build/build/javascript
RUN apk add --update --no-cache npm >> /dev/null
ENV NODE_ENV=production
RUN cd /build/build/javascript && npm install --quiet --no-progress >> /dev/null && npm install -g cssnano postcss postcss-cli --quiet --no-progress --save-dev >> /dev/null && ./node_modules/.bin/tailwind build > /build/tailwind.min.css
RUN npx postcss /build/tailwind.min.css > /build/prod-tailwind.min.css
SAVE ARTIFACT /build/prod-tailwind.min.css prod-tailwind.min.css
package:
RUN apk add --update --no-cache zip >> /dev/null
ARG TARGETPLATFORM # provided by Earthly
IF [ "$TARGETPLATFORM" = "linux/amd64" ]
ARG NAME=linux-64bit
ELSE IF [ "$TARGETPLATFORM" = "linux/386" ]
ARG NAME=linux-32bit
ELSE IF [ "$TARGETPLATFORM" = "linux/arm64" ]
ARG NAME=linux-arm64
ELSE IF [ "$TARGETPLATFORM" = "linux/arm/v7" ]
ARG NAME=linux-arm7
ELSE IF [ "$TARGETPLATFORM" = "darwin/amd64" ]
ARG NAME=macOS-64bit
ELSE
ARG NAME=custom
END
COPY (+build/webroot --platform $TARGETPLATFORM) /build/dist/webroot
COPY (+build/owncast --platform $TARGETPLATFORM) /build/dist/owncast
COPY (+build/README.md --platform $TARGETPLATFORM) /build/dist/README.md
ENV ZIPNAME owncast-$version-$NAME.zip
RUN cd /build/dist && zip -r -q -8 /build/dist/owncast.zip .
SAVE ARTIFACT /build/dist/owncast.zip owncast.zip AS LOCAL dist/$ZIPNAME
docker:
ARG image=ghcr.io/owncast/owncast
ARG tag=develop
ARG TARGETPLATFORM
FROM --platform=$TARGETPLATFORM alpine:latest
RUN apk update && apk add --no-cache ffmpeg ffmpeg-libs ca-certificates unzip && update-ca-certificates
WORKDIR /app
COPY --platform=$TARGETPLATFORM +package/owncast.zip /app
RUN unzip -x owncast.zip && mkdir data
ENTRYPOINT ["/app/owncast"]
EXPOSE 8080 1935
SAVE IMAGE --push $image:$tag

View File

@ -48,7 +48,9 @@ Owncast is an open source, self-hosted, decentralized, single user live video st
<div>
<img alt="GitHub all releases" src="https://img.shields.io/github/downloads/owncast/owncast/total?style=for-the-badge">
<a href="https://hub.docker.com/r/gabekangas/owncast">
<img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/gabekangas/owncast?style=for-the-badge">
</a>
<a href="https://github.com/owncast/owncast/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22">
<img alt="GitHub issues by-label" src="https://img.shields.io/github/issues-raw/owncast/owncast/good%20first%20issue?style=for-the-badge">
</a>

View File

@ -4,6 +4,7 @@ import (
"context"
"crypto/x509"
"encoding/pem"
"fmt"
"net/http"
"net/url"
"strings"
@ -21,7 +22,7 @@ import (
func handle(request apmodels.InboxRequest) {
if verified, err := Verify(request.Request); err != nil {
log.Debugln("Error in attempting to verify request", err)
log.Errorln("Error in attempting to verify request", err)
return
} else if !verified {
log.Debugln("Request failed verification", err)
@ -35,6 +36,7 @@ func handle(request apmodels.InboxRequest) {
// Verify will Verify the http signature of an inbound request as well as
// check it against the list of blocked domains.
// nolint: cyclop
func Verify(request *http.Request) (bool, error) {
verifier, err := httpsig.NewVerifier(request)
if err != nil {
@ -51,6 +53,10 @@ func Verify(request *http.Request) (bool, error) {
}
signature := request.Header.Get("signature")
if signature == "" {
return false, errors.New("http signature header not found in request")
}
var algorithmString string
signatureComponents := strings.Split(signature, ",")
for _, component := range signatureComponents {
@ -66,26 +72,31 @@ func Verify(request *http.Request) (bool, error) {
return false, errors.New("Unable to determine algorithm to verify request")
}
actor, err := resolvers.GetResolvedActorFromIRI(pubKeyID.String())
publicKey, err := resolvers.GetResolvedPublicKeyFromIRI(pubKeyID.String())
if err != nil {
return false, errors.Wrap(err, "failed to resolve actor from IRI to fetch key")
}
if actor.ActorIri == nil {
return false, errors.New("actor IRI is empty")
var publicKeyActorIRI *url.URL
if ownerProp := publicKey.GetW3IDSecurityV1Owner(); ownerProp != nil {
publicKeyActorIRI = ownerProp.Get()
}
if publicKeyActorIRI == nil {
return false, errors.New("public key owner IRI is empty")
}
// Test to see if the actor is in the list of blocked federated domains.
if isBlockedDomain(actor.ActorIri.Hostname()) {
if isBlockedDomain(publicKeyActorIRI.Hostname()) {
return false, errors.New("domain is blocked")
}
// If actor is specifically blocked, then fail validation.
if blocked, err := isBlockedActor(actor.ActorIri); err != nil || blocked {
if blocked, err := isBlockedActor(publicKeyActorIRI); err != nil || blocked {
return false, err
}
key := actor.W3IDSecurityV1PublicKey.Begin().Get().GetW3IDSecurityV1PublicKeyPem().Get()
key := publicKey.GetW3IDSecurityV1PublicKeyPem().Get()
block, _ := pem.Decode([]byte(key))
if block == nil {
log.Errorln("failed to parse PEM block containing the public key")
@ -98,15 +109,25 @@ func Verify(request *http.Request) (bool, error) {
return false, errors.Wrap(err, "failed to parse DER encoded public key")
}
var algorithm httpsig.Algorithm = httpsig.Algorithm(algorithmString)
// The verifier will verify the Digest in addition to the HTTP signature
if err := verifier.Verify(parsedKey, algorithm); err != nil {
log.Warnln("verification error for", pubKeyID, err)
return false, errors.Wrap(err, "verification error: "+pubKeyID.String())
algos := []httpsig.Algorithm{
httpsig.Algorithm(algorithmString), // try stated algorithm first then other common algorithms
httpsig.RSA_SHA256, // <- used by almost all fedi software
httpsig.RSA_SHA512,
}
// The verifier will verify the Digest in addition to the HTTP signature
triedAlgos := make(map[httpsig.Algorithm]error)
for _, algorithm := range algos {
if _, tried := triedAlgos[algorithm]; !tried {
err := verifier.Verify(parsedKey, algorithm)
if err == nil {
return true, nil
}
triedAlgos[algorithm] = err
}
}
return false, fmt.Errorf("http signature verification error(s) for: %s: %+v", pubKeyID.String(), triedAlgos)
}
func isBlockedDomain(domain string) bool {

View File

@ -122,6 +122,72 @@ func GetResolvedActorFromActorProperty(actor vocab.ActivityStreamsActorProperty)
return apActor, err
}
// GetResolvedPublicKeyFromIRI will resolve a publicKey IRI string to a vocab.W3IDSecurityV1PublicKey.
func GetResolvedPublicKeyFromIRI(publicKeyIRI string) (vocab.W3IDSecurityV1PublicKey, error) {
var err error
var pubkey vocab.W3IDSecurityV1PublicKey
resolved := false
personCallback := func(c context.Context, person vocab.ActivityStreamsPerson) error {
if pkProp := person.GetW3IDSecurityV1PublicKey(); pkProp != nil {
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
if iter.IsW3IDSecurityV1PublicKey() {
pubkey = iter.Get()
resolved = true
return nil
}
}
}
return errors.New("error deriving publickey from activitystreamsperson")
}
serviceCallback := func(c context.Context, service vocab.ActivityStreamsService) error {
if pkProp := service.GetW3IDSecurityV1PublicKey(); pkProp != nil {
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
if iter.IsW3IDSecurityV1PublicKey() {
pubkey = iter.Get()
resolved = true
return nil
}
}
}
return errors.New("error deriving publickey from activitystreamsservice")
}
applicationCallback := func(c context.Context, app vocab.ActivityStreamsApplication) error {
if pkProp := app.GetW3IDSecurityV1PublicKey(); pkProp != nil {
for iter := pkProp.Begin(); iter != pkProp.End(); iter = iter.Next() {
if iter.IsW3IDSecurityV1PublicKey() {
pubkey = iter.Get()
resolved = true
return nil
}
}
}
return errors.New("error deriving publickey from activitystreamsapp")
}
pubkeyCallback := func(c context.Context, pk vocab.W3IDSecurityV1PublicKey) error {
pubkey = pk
resolved = true
return nil
}
if e := ResolveIRI(context.Background(), publicKeyIRI, personCallback, serviceCallback, applicationCallback, pubkeyCallback); e != nil {
err = e
}
if err != nil {
err = errors.Wrap(err, "error resolving publickey from iri")
}
if !resolved {
err = errors.New("error resolving publickey from iri")
}
return pubkey, err
}
// GetResolvedActorFromIRI will resolve an IRI string to a fully populated actor.
func GetResolvedActorFromIRI(personOrServiceIRI string) (apmodels.ActivityPubActor, error) {
var err error

View File

@ -68,7 +68,7 @@ func HandleCallbackCode(code, state string) (*Request, *Response, error) {
var response Response
if err := json.Unmarshal(body, &response); err != nil {
return nil, nil, errors.Wrap(err, "unable to parse IndieAuth response")
return nil, nil, errors.Wrap(err, "unable to parse IndieAuth response: "+string(body))
}
if response.Error != "" || response.ErrorDescription != "" {

View File

@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@babel/runtime": {
"version": "7.17.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz",
"integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==",
"version": "7.18.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.3.tgz",
"integrity": "sha512-38Y8f7YUhce/K7RMwTp7m0uCumpv9hZkitCbBClqQIow1qSbCvGkcegKOXpEWCQLfWmevgRiWokZ1GkpfhbZug==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
@ -296,7 +296,7 @@
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="
},
"brace-expansion": {
"version": "1.1.11",
@ -358,9 +358,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001335",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001335.tgz",
"integrity": "sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w=="
"version": "1.0.30001344",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz",
"integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g=="
},
"chalk": {
"version": "4.1.2",
@ -454,7 +454,7 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
},
"color-string": {
"version": "1.9.1",
@ -479,7 +479,7 @@
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
},
"css-declaration-sorter": {
"version": "6.2.2",
@ -535,26 +535,26 @@
}
},
"cssnano-preset-default": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.7.tgz",
"integrity": "sha512-JiKP38ymZQK+zVKevphPzNSGHSlTI+AOwlasoSRtSVMUU285O7/6uZyd5NbW92ZHp41m0sSHe6JoZosakj63uA==",
"version": "5.2.10",
"resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.2.10.tgz",
"integrity": "sha512-H8TJRhTjBKVOPltp9vr9El9I+IfYsOMhmXdK0LwdvwJcxYX9oWkY7ctacWusgPWAgQq1vt/WO8v+uqpfLnM7QA==",
"dev": true,
"requires": {
"css-declaration-sorter": "^6.2.2",
"cssnano-utils": "^3.1.0",
"postcss-calc": "^8.2.3",
"postcss-colormin": "^5.3.0",
"postcss-convert-values": "^5.1.0",
"postcss-discard-comments": "^5.1.1",
"postcss-convert-values": "^5.1.2",
"postcss-discard-comments": "^5.1.2",
"postcss-discard-duplicates": "^5.1.0",
"postcss-discard-empty": "^5.1.1",
"postcss-discard-overridden": "^5.1.0",
"postcss-merge-longhand": "^5.1.4",
"postcss-merge-rules": "^5.1.1",
"postcss-merge-longhand": "^5.1.5",
"postcss-merge-rules": "^5.1.2",
"postcss-minify-font-values": "^5.1.0",
"postcss-minify-gradients": "^5.1.1",
"postcss-minify-params": "^5.1.2",
"postcss-minify-selectors": "^5.2.0",
"postcss-minify-params": "^5.1.3",
"postcss-minify-selectors": "^5.2.1",
"postcss-normalize-charset": "^5.1.0",
"postcss-normalize-display-values": "^5.1.0",
"postcss-normalize-positions": "^5.1.0",
@ -589,7 +589,7 @@
"defined": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
"integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ=="
},
"dependency-graph": {
"version": "0.11.0",
@ -598,13 +598,13 @@
"dev": true
},
"detective": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
"integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
"integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
"requires": {
"acorn-node": "^1.6.1",
"acorn-node": "^1.8.2",
"defined": "^1.0.0",
"minimist": "^1.1.1"
"minimist": "^1.2.6"
}
},
"dir-glob": {
@ -653,9 +653,9 @@
}
},
"electron-to-chromium": {
"version": "1.4.129",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.129.tgz",
"integrity": "sha512-GgtN6bsDtHdtXJtlMYZWGB/uOyjZWjmRDumXTas7dGBaB9zUyCjzHet1DY2KhyHN8R0GLbzZWqm4efeddqqyRQ=="
"version": "1.4.141",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.141.tgz",
"integrity": "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA=="
},
"emoji-regex": {
"version": "8.0.0",
@ -676,12 +676,12 @@
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
},
"fast-glob": {
"version": "3.2.11",
@ -736,7 +736,7 @@
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
"requires": {
"graceful-fs": "^4.1.6"
}
@ -746,7 +746,7 @@
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
},
"fsevents": {
"version": "2.3.2",
@ -761,9 +761,9 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"fuzzysort": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-1.2.1.tgz",
"integrity": "sha512-egTSF3U6H6T9tXtAhEm5P5guSSDjd96/NUWrbmoGlIu3ATMdXra13gwQdEFRY6ehsFe8xec7UnQz+k34CGWCIg=="
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-1.9.0.tgz",
"integrity": "sha512-MOxCT0qLTwLqmEwc7UtU045RKef7mc8Qz8eR4r2bLNEq9dy/c3ZKMEFp6IEst69otkQdFZ4FfgH2dmZD+ddX1g=="
},
"get-caller-file": {
"version": "2.0.5",
@ -778,14 +778,14 @@
"dev": true
},
"glob": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
"integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
@ -838,7 +838,7 @@
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
},
"htm": {
"version": "3.1.1",
@ -872,12 +872,12 @@
"individual": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
"integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c="
"integrity": "sha512-pWt8hBCqJsUWI/HtcfWod7+N9SgAqyPEaF7JQjwzjn5vGrpg6aQ5qeAFQ7dx//UH4J1O+7xqew+gCeeFt6xN/g=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
@ -913,7 +913,7 @@
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true
},
"is-fullwidth-code-point": {
@ -970,13 +970,13 @@
"lodash.memoize": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
"integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
"dev": true
},
"lodash.uniq": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
"integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
"integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
"dev": true
},
"m3u8-parser": {
@ -1062,9 +1062,9 @@
}
},
"nanoid": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz",
"integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==",
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"dev": true
},
"node-emoji": {
@ -1076,9 +1076,9 @@
}
},
"node-releases": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz",
"integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ=="
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz",
"integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q=="
},
"normalize-path": {
"version": "3.0.0",
@ -1271,18 +1271,19 @@
}
},
"postcss-convert-values": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.0.tgz",
"integrity": "sha512-GkyPbZEYJiWtQB0KZ0X6qusqFHUepguBCNFi9t5JJc7I2OTXG7C0twbTLvCfaKOLl3rSXmpAwV7W5txd91V84g==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz",
"integrity": "sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g==",
"dev": true,
"requires": {
"browserslist": "^4.20.3",
"postcss-value-parser": "^4.2.0"
}
},
"postcss-discard-comments": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.1.tgz",
"integrity": "sha512-5JscyFmvkUxz/5/+TB3QTTT9Gi9jHkcn8dcmmuN68JQcv3aQg4y88yEHHhwFB52l/NkaJ43O0dbksGMAo49nfQ==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz",
"integrity": "sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==",
"dev": true
},
"postcss-discard-duplicates": {
@ -1403,9 +1404,9 @@
}
},
"postcss-merge-longhand": {
"version": "5.1.4",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.4.tgz",
"integrity": "sha512-hbqRRqYfmXoGpzYKeW0/NCZhvNyQIlQeWVSao5iKWdyx7skLvCfQFGIUsP9NUs3dSbPac2IC4Go85/zG+7MlmA==",
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.1.5.tgz",
"integrity": "sha512-NOG1grw9wIO+60arKa2YYsrbgvP6tp+jqc7+ZD5/MalIw234ooH2C6KlR6FEn4yle7GqZoBxSK1mLBE9KPur6w==",
"dev": true,
"requires": {
"postcss-value-parser": "^4.2.0",
@ -1413,9 +1414,9 @@
}
},
"postcss-merge-rules": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.1.tgz",
"integrity": "sha512-8wv8q2cXjEuCcgpIB1Xx1pIy8/rhMPIQqYKNzEdyx37m6gpq83mQQdCxgIkFgliyEnKvdwJf/C61vN4tQDq4Ww==",
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.1.2.tgz",
"integrity": "sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
@ -1445,9 +1446,9 @@
}
},
"postcss-minify-params": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.2.tgz",
"integrity": "sha512-aEP+p71S/urY48HWaRHasyx4WHQJyOYaKpQ6eXl8k0kxg66Wt/30VR6/woh8THgcpRbonJD5IeD+CzNhPi1L8g==",
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.1.3.tgz",
"integrity": "sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg==",
"dev": true,
"requires": {
"browserslist": "^4.16.6",
@ -1456,9 +1457,9 @@
}
},
"postcss-minify-selectors": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.0.tgz",
"integrity": "sha512-vYxvHkW+iULstA+ctVNx0VoRAR4THQQRkG77o0oa4/mBS0OzGvvzLIvHDv/nNEM0crzN2WIyFU5X7wZhaUK3RA==",
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz",
"integrity": "sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==",
"dev": true,
"requires": {
"postcss-selector-parser": "^6.0.5"
@ -1975,9 +1976,9 @@
"dev": true
},
"nth-check": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz",
"integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"dev": true,
"requires": {
"boolbase": "^1.0.0"
@ -2185,9 +2186,9 @@
"dev": true
},
"yargs": {
"version": "17.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz",
"integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==",
"version": "17.5.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz",
"integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==",
"dev": true,
"requires": {
"cliui": "^7.0.2",

View File

@ -0,0 +1,14 @@
#!/bin/sh
# Docker build
# Must authenticate first: https://docs.github.com/en/packages/using-github-packages-with-your-projects-ecosystem/configuring-docker-for-use-with-github-packages#authenticating-to-github-packages
DOCKER_IMAGE="owncast-earthly"
DATE=$(date +"%Y%m%d")
VERSION="${DATE}-nightly"
echo "Building Docker image ${DOCKER_IMAGE}..."
# Change to the root directory of the repository
cd $(git rev-parse --show-toplevel)
earthly --ci --push +docker-all --image="ghcr.io/owncast/${DOCKER_IMAGE}" --tag=nightly --version="${VERSION}"

View File

@ -6,13 +6,16 @@ import (
ia "github.com/owncast/owncast/auth/indieauth"
"github.com/owncast/owncast/controllers"
"github.com/owncast/owncast/router/middleware"
)
// HandleAuthEndpoint will handle the IndieAuth auth endpoint.
func HandleAuthEndpoint(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet {
// Require the GET request for IndieAuth to be behind admin login.
handleAuthEndpointGet(w, r)
f := middleware.RequireAdminAuth(handleAuthEndpointGet)
f(w, r)
return
} else if r.Method == http.MethodPost {
handleAuthEndpointPost(w, r)
} else {

View File

@ -3,9 +3,11 @@ package storageproviders
import (
"bufio"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/owncast/owncast/core/data"
"github.com/owncast/owncast/core/playlist"
@ -176,6 +178,14 @@ func (s *S3Storage) Save(filePath string, retryCount int) (string, error) {
}
func (s *S3Storage) connectAWS() *session.Session {
t := http.DefaultTransport.(*http.Transport).Clone()
t.MaxIdleConnsPerHost = 100
httpClient := &http.Client{
Timeout: 10 * time.Second,
Transport: t,
}
creds := credentials.NewStaticCredentials(s.s3AccessKey, s.s3Secret, "")
_, err := creds.Get()
if err != nil {
@ -184,6 +194,7 @@ func (s *S3Storage) connectAWS() *session.Session {
sess, err := session.NewSession(
&aws.Config{
HTTPClient: httpClient,
Region: aws.String(s.s3Region),
Credentials: creds,
Endpoint: aws.String(s.s3Endpoint),

File diff suppressed because one or more lines are too long

12
go.mod
View File

@ -4,14 +4,14 @@ go 1.17
require (
github.com/amalfra/etag v1.0.0
github.com/aws/aws-sdk-go v1.43.44
github.com/aws/aws-sdk-go v1.44.28
github.com/go-fed/activity v1.0.1-0.20210803212804-d866ba75dd0f
github.com/go-fed/httpsig v1.1.0
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gorilla/websocket v1.5.0
github.com/grafov/m3u8 v0.11.1
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
github.com/mattn/go-sqlite3 v1.14.12
github.com/mattn/go-sqlite3 v1.14.13
github.com/microcosm-cc/bluemonday v1.0.18
github.com/mssola/user_agent v0.5.3
github.com/nareix/joy5 v0.0.0-20210317075623-2c912ca30590
@ -20,7 +20,7 @@ require (
github.com/schollz/sqlite3dump v1.3.1
github.com/sirupsen/logrus v1.8.1
github.com/teris-io/shortid v0.0.0-20201117134242-e59966efd125
github.com/yuin/goldmark v1.4.11
github.com/yuin/goldmark v1.4.12
golang.org/x/mod v0.5.1
golang.org/x/time v0.0.0-20220411224347-583f2d630306
mvdan.cc/xurls v1.1.0
@ -35,11 +35,11 @@ require (
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861
golang.org/x/sys v0.0.0-20220325203850-36772127a21f // indirect
golang.org/x/net v0.0.0-20220607020251-c690dde0001d
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
)
require github.com/prometheus/client_golang v1.12.1
require github.com/prometheus/client_golang v1.12.2
require (
github.com/beorn7/perks v1.0.1 // indirect

14
go.sum
View File

@ -48,6 +48,8 @@ github.com/aws/aws-sdk-go v1.43.43 h1:1L06qzQvl4aC3Skfh5rV7xVhGHjIZoHcqy16NoyQ1o
github.com/aws/aws-sdk-go v1.43.43/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.43.44 h1:t+97cY4ScE/czlNlK5iikUGi7w1fC0uop1OUalDIRT4=
github.com/aws/aws-sdk-go v1.43.44/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aws/aws-sdk-go v1.44.28 h1:h/OAqEqY18wq//v6h4GNPMmCkxuzSDrWuGyrvSiRqf4=
github.com/aws/aws-sdk-go v1.44.28/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@ -193,6 +195,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I=
github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo=
@ -232,6 +236,8 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.2 h1:51L9cDoUHVrXx4zWYlcLQIZ+d+VXHgqnYKkIuq4g/34=
github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
@ -281,6 +287,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.11 h1:i45YIzqLnUc2tGaTlJCyUxSG8TvgyGqhqOZOUKIjJ6w=
github.com/yuin/goldmark v1.4.11/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg=
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@ -368,6 +376,10 @@ golang.org/x/net v0.0.0-20220420153159-1850ba15e1be h1:yx80W7nvY5ySWpaU8UWaj5o9e
golang.org/x/net v0.0.0-20220420153159-1850ba15e1be/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861 h1:yssD99+7tqHWO5Gwh81phT+67hg+KttniBr6UnEXOY8=
golang.org/x/net v0.0.0-20220421235706-1d1ef9303861/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220531201128-c960675eff93 h1:MYimHLfoXEpOhqd/zgoA/uoXzHB86AEky4LAx5ij9xA=
golang.org/x/net v0.0.0-20220531201128-c960675eff93/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d h1:4SFsTMi4UahlKoloni7L4eYzhFRifURQLw+yv0QDCx8=
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -428,6 +440,8 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220325203850-36772127a21f h1:TrmogKRsSOxRMJbLYGrB4SBbW+LJcEllYBLME5Zk5pU=
golang.org/x/sys v0.0.0-20220325203850-36772127a21f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

@ -1,8 +1,8 @@
openapi: 3.0.1
info:
title: Owncast
description: Owncast is a self-hosted live video and web chat server for use with existing popular broadcasting software. The following APIs represent the state in the development branch.
version: '0.0.11'
description: Owncast is a self-hosted live video and web chat server for use with existing popular broadcasting software.
version: '0.0.12'
contact:
name: Gabe Kangas
email: gabek@real-ity.com
@ -334,7 +334,12 @@ components:
example: https://mastodon.cloud/users/gabektest
type:
type: string
enum: [FEDIVERSE_ENGAGEMENT_FOLLOW, FEDIVERSE_ENGAGEMENT_LIKE, FEDIVERSE_ENGAGEMENT_REPOST]
enum:
[
FEDIVERSE_ENGAGEMENT_FOLLOW,
FEDIVERSE_ENGAGEMENT_LIKE,
FEDIVERSE_ENGAGEMENT_REPOST,
]
securitySchemes:
AdminBasicAuth:
@ -1439,7 +1444,7 @@ paths:
/api/admin/config/federation/enable:
post:
summary: Enable or disable federated social features.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1451,11 +1456,10 @@ paths:
schema:
$ref: '#/components/schemas/BooleanValue'
/api/admin/config/federation/private:
post:
summary: Enable or disable private federation mode.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1467,11 +1471,10 @@ paths:
schema:
$ref: '#/components/schemas/BooleanValue'
/api/admin/config/federation/showengagement:
post:
summary: Enable or disable Federation activity showing in chat.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1486,7 +1489,7 @@ paths:
/api/admin/config/federation/username:
post:
summary: Set the username you are seen as on the fediverse.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1501,7 +1504,7 @@ paths:
/api/admin/config/federation/livemessage:
post:
summary: Set the message sent to the fediverse when this instance goes live.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1516,7 +1519,7 @@ paths:
/api/admin/config/federation/blockdomains:
post:
summary: Save a collection of domains that should be ignored on the fediverse.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1535,7 +1538,7 @@ paths:
/api/admin/federation/send:
post:
summary: Manually send a message to the fediverse from this instance.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1552,7 +1555,7 @@ paths:
/api/admin/federation/actions:
get:
summary: Get a list of accepted actions that took place on the Fediverse.
tags: ["Admin"]
tags: ['Admin']
security:
- AdminBasicAuth: []
responses:
@ -1565,7 +1568,6 @@ paths:
items:
$ref: '#/components/schemas/FederatedAction'
/api/integrations/streamtitle:
post:
summary: Set the stream title.
@ -2126,3 +2128,13 @@ paths:
'200':
description: The list of default names have been updated.
$ref: '#/components/responses/BasicResponse'
/api/admin/prometheus:
get:
tags: ['Admin']
security:
- AdminBasicAuth: []
summary: Return Prometheus-compatible scraper metrics.
responses:
'200':
description: Prometheus-compatible scraper values.

View File

@ -22,8 +22,10 @@ func RequireActivityPubOrRedirect(handler http.HandlerFunc) http.HandlerFunc {
}
acceptedContentTypes := []string{"application/json", "application/json+ld", "application/activity+json", `application/ld+json; profile="https://www.w3.org/ns/activitystreams"`}
acceptString := r.Header.Get("Accept")
accept := strings.Split(acceptString, ",")
var accept []string
for _, a := range r.Header.Values("Accept") {
accept = append(accept, strings.Split(a, ",")...)
}
for _, singleType := range accept {
if _, accepted := utils.FindInSlice(acceptedContentTypes, strings.TrimSpace(singleType)); accepted {

View File

@ -355,7 +355,7 @@ func Start() error {
// Start auth flow
http.HandleFunc("/api/auth/indieauth", middleware.RequireUserAccessToken(indieauth.StartAuthFlow))
http.HandleFunc("/api/auth/indieauth/callback", middleware.RequireAdminAuth(indieauth.HandleRedirect))
http.HandleFunc("/api/auth/indieauth/callback", indieauth.HandleRedirect)
http.HandleFunc("/api/auth/provider/indieauth", indieauth.HandleAuthEndpoint)
http.HandleFunc("/api/auth/fediverse", middleware.RequireUserAccessToken(fediverseauth.RegisterFediverseOTPRequest))

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

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

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

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

View File

@ -1 +1 @@
self.__BUILD_MANIFEST=function(s,c,a,e,t,i,n,f,o,d,h,g,u,r,k){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,c,a,e,t,i,n,h,"static/chunks/2494-8114e9c6571377d1.js","static/chunks/pages/index-e0ac83ceaf99b5f0.js"],"/_error":["static/chunks/pages/_error-785557186902809b.js"],"/access-tokens":[s,c,a,"static/chunks/pages/access-tokens-d328b918d1f9b3d4.js"],"/actions":[s,c,"static/chunks/pages/actions-9278698db4cd1a16.js"],"/chat/messages":[g,s,c,a,n,u,"static/chunks/pages/chat/messages-0df125d8b9455827.js"],"/chat/users":[g,s,c,a,e,n,"static/chunks/6489-cea2e8971ed16ad4.js",u,"static/chunks/pages/chat/users-201d39dd28f27416.js"],"/config-chat":["static/chunks/pages/config-chat-bacb12d23264144b.js"],"/config-federation":["static/chunks/1829-f5c4fb462b2f7e98.js","static/chunks/pages/config-federation-ea0f018fb4193b61.js"],"/config-notify":["static/chunks/pages/config-notify-10a8844dc11ca4b2.js"],"/config-public-details":[s,c,f,"static/css/e773f9ad06a56dc3.css","static/chunks/2589-e1721280387f6322.js",r,"static/chunks/pages/config-public-details-94ff52653eb2586e.js"],"/config-server-details":[k,"static/chunks/pages/config-server-details-cd516688accb84d3.js"],"/config-social-items":[s,c,r,"static/chunks/pages/config-social-items-42e2ed4eed8d4dd2.js"],"/config-storage":["static/chunks/5473-623385148d67cba2.js","static/chunks/pages/config-storage-5ff120c715bfdb04.js"],"/config-video":[s,c,k,"static/chunks/1556-d7a4de19826e46f3.js","static/chunks/pages/config-video-32d86e0ba98dc6fe.js"],"/federation/actions":[s,c,a,"static/chunks/pages/federation/actions-7cfffddef3b58d86.js"],"/federation/followers":[s,c,a,e,"static/chunks/pages/federation/followers-d2d105c342c79f98.js"],"/hardware-info":[o,a,e,t,i,d,f,"static/chunks/pages/hardware-info-4723b20a84e4f461.js"],"/help":[e,t,"static/chunks/6132-187b2bf3e1265f44.js","static/chunks/pages/help-deeb1c0f667c7d75.js"],"/logs":[s,c,a,h,"static/chunks/pages/logs-df4b23b85b8ac818.js"],"/stream-health":[o,s,a,e,t,i,d,"static/chunks/pages/stream-health-5edc91e4fa00ba5c.js"],"/upgrade":[s,c,"static/chunks/9655-6347f487aa1205af.js","static/chunks/pages/upgrade-6cb31f6812e79694.js"],"/viewer-info":[o,s,c,a,e,t,i,n,d,f,"static/chunks/pages/viewer-info-03fcbea265510389.js"],"/webhooks":[s,c,"static/chunks/pages/webhooks-651cb241952e0e4a.js"],sortedPages:["/","/_app","/_error","/access-tokens","/actions","/chat/messages","/chat/users","/config-chat","/config-federation","/config-notify","/config-public-details","/config-server-details","/config-social-items","/config-storage","/config-video","/federation/actions","/federation/followers","/hardware-info","/help","/logs","/stream-health","/upgrade","/viewer-info","/webhooks"]}}("static/chunks/1741-d9d648ade4ad86b9.js","static/chunks/6003-f37682e25271f05f.js","static/chunks/8091-5bc21baa6d0d3232.js","static/chunks/8879-af8bf87fdc518c08.js","static/chunks/7751-48959ec0f11e9080.js","static/chunks/4763-7fd93797a527a971.js","static/chunks/5533-096cc7dc6703128f.js","static/chunks/7910-699eb8ed3467dc00.js","static/chunks/36bcf0ca-110fd889741d5f41.js","static/chunks/1080-1a127ea7f5a8eb3d.js","static/chunks/2429-ccb4d7fa1648dd38.js","static/chunks/29107295-4a69275373f23f88.js","static/chunks/1371-f41477e42ee50603.js","static/chunks/1017-0760c7f39ffcc2a7.js","static/chunks/4578-afc9eff4fbf5ecb1.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
self.__BUILD_MANIFEST=function(s,c,a,e,t,i,f,n,o,d,h,g,u,b,r){return{__rewrites:{beforeFiles:[],afterFiles:[],fallback:[]},"/":[s,c,a,e,t,i,f,h,"static/chunks/2494-8114e9c6571377d1.js","static/chunks/pages/index-e0ac83ceaf99b5f0.js"],"/_error":["static/chunks/pages/_error-785557186902809b.js"],"/access-tokens":[s,c,a,"static/chunks/pages/access-tokens-d328b918d1f9b3d4.js"],"/actions":[s,c,"static/chunks/pages/actions-9278698db4cd1a16.js"],"/chat/messages":[g,s,c,a,f,u,"static/chunks/pages/chat/messages-0df125d8b9455827.js"],"/chat/users":[g,s,c,a,e,f,"static/chunks/6489-cea2e8971ed16ad4.js",u,"static/chunks/pages/chat/users-c3f6235e6932151e.js"],"/config-chat":["static/chunks/pages/config-chat-bacb12d23264144b.js"],"/config-federation":["static/chunks/1829-f5c4fb462b2f7e98.js","static/chunks/pages/config-federation-ea0f018fb4193b61.js"],"/config-notify":["static/chunks/pages/config-notify-10a8844dc11ca4b2.js"],"/config-public-details":[s,c,n,"static/css/e773f9ad06a56dc3.css","static/chunks/2589-c48f3b04b9a6c7ce.js",b,"static/chunks/pages/config-public-details-94ff52653eb2586e.js"],"/config-server-details":[r,"static/chunks/pages/config-server-details-cd516688accb84d3.js"],"/config-social-items":[s,c,b,"static/chunks/pages/config-social-items-42e2ed4eed8d4dd2.js"],"/config-storage":["static/chunks/5473-623385148d67cba2.js","static/chunks/pages/config-storage-5ff120c715bfdb04.js"],"/config-video":[s,c,r,"static/chunks/1556-f79a922e799c7a06.js","static/chunks/pages/config-video-32d86e0ba98dc6fe.js"],"/federation/actions":[s,c,a,"static/chunks/pages/federation/actions-7cfffddef3b58d86.js"],"/federation/followers":[s,c,a,e,"static/chunks/pages/federation/followers-d2d105c342c79f98.js"],"/hardware-info":[o,a,e,t,i,d,n,"static/chunks/pages/hardware-info-4723b20a84e4f461.js"],"/help":[e,t,"static/chunks/6132-4fc73fe4cc2a426e.js","static/chunks/pages/help-deeb1c0f667c7d75.js"],"/logs":[s,c,a,h,"static/chunks/pages/logs-df4b23b85b8ac818.js"],"/stream-health":[o,s,a,e,t,i,d,"static/chunks/pages/stream-health-4a811c8adeb950de.js"],"/upgrade":[s,c,"static/chunks/9655-722bcfb83a61ab83.js","static/chunks/pages/upgrade-6cb31f6812e79694.js"],"/viewer-info":[o,s,c,a,e,t,i,f,d,n,"static/chunks/pages/viewer-info-03fcbea265510389.js"],"/webhooks":[s,c,"static/chunks/pages/webhooks-651cb241952e0e4a.js"],sortedPages:["/","/_app","/_error","/access-tokens","/actions","/chat/messages","/chat/users","/config-chat","/config-federation","/config-notify","/config-public-details","/config-server-details","/config-social-items","/config-storage","/config-video","/federation/actions","/federation/followers","/hardware-info","/help","/logs","/stream-health","/upgrade","/viewer-info","/webhooks"]}}("static/chunks/1741-d9d648ade4ad86b9.js","static/chunks/6003-f37682e25271f05f.js","static/chunks/8091-5bc21baa6d0d3232.js","static/chunks/8879-af8bf87fdc518c08.js","static/chunks/7751-48959ec0f11e9080.js","static/chunks/4763-7fd93797a527a971.js","static/chunks/5533-096cc7dc6703128f.js","static/chunks/7910-699eb8ed3467dc00.js","static/chunks/36bcf0ca-110fd889741d5f41.js","static/chunks/1080-1a127ea7f5a8eb3d.js","static/chunks/2429-ccb4d7fa1648dd38.js","static/chunks/29107295-4a69275373f23f88.js","static/chunks/1371-f41477e42ee50603.js","static/chunks/1017-0760c7f39ffcc2a7.js","static/chunks/4578-afc9eff4fbf5ecb1.js"),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

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

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

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

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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -96,8 +96,9 @@ export default class FediverseFollowModal extends Component {
return html`
<div class="bg-gray-100 bg-center bg-no-repeat p-4">
<p class="text-gray-700 text-md">
By following this stream you'll get posts and notifications such as
when it goes live.
By following this stream on the Fediverse you'll receive updates when
it goes live, get posts from the streamer, and be featured as a
follower.
</p>
<div

View File

@ -27,7 +27,7 @@ How to help with this? The Owncast Latency Compensator will:
- Completely give up on all compensation if too many buffering events occur.
*/
const REBUFFER_EVENT_LIMIT = 5; // Max number of buffering events before we stop compensating for latency.
const REBUFFER_EVENT_LIMIT = 4; // Max number of buffering events before we stop compensating for latency.
const MIN_BUFFER_DURATION = 200; // Min duration a buffer event must last to be counted.
const MAX_SPEEDUP_RATE = 1.08; // The playback rate when compensating for latency.
const MAX_SPEEDUP_RAMP = 0.02; // The max amount we will increase the playback rate at once.
@ -47,6 +47,7 @@ const STARTUP_WAIT_TIME = 10 * 1000; // The amount of time after we start up tha
class LatencyCompensator {
constructor(player) {
this.player = player;
this.playing = false;
this.enabled = false;
this.running = false;
this.inTimeout = false;
@ -59,14 +60,25 @@ class LatencyCompensator {
this.lastJumpOccurred = null;
this.startupTime = new Date();
this.clockSkewMs = 0;
this.currentLatency = null;
// Keep track of all the latencies we encountered buffering events
// in order to determine a new minimum latency.
this.bufferedAtLatency = [];
this.player.on('playing', this.handlePlaying.bind(this));
this.player.on('pause', this.handlePause.bind(this));
this.player.on('error', this.handleError.bind(this));
this.player.on('waiting', this.handleBuffering.bind(this));
this.player.on('stalled', this.handleBuffering.bind(this));
this.player.on('ended', this.handleEnded.bind(this));
this.player.on('canplaythrough', this.handlePlaying.bind(this));
this.player.on('canplay', this.handlePlaying.bind(this));
this.check = this.check.bind(this);
this.start = this.start.bind(this);
this.enable = this.enable.bind(this);
this.countBufferingEvent = this.countBufferingEvent.bind(this);
}
// To keep our client clock in sync with the server clock to determine
@ -97,7 +109,6 @@ class LatencyCompensator {
}
if (this.inTimeout) {
console.log('in timeout...');
return;
}
@ -162,13 +173,27 @@ class LatencyCompensator {
}
// How far away from live edge do we stop the compensator.
const minLatencyThreshold = Math.max(
const computedMinLatencyThreshold = Math.max(
MIN_LATENCY,
segment.duration * 1000 * LOWEST_LATENCY_SEGMENT_LENGTH_MULTIPLIER
);
// Create an array of all the buffering events in the past along with
// the computed min latency above.
const targetLatencies = this.bufferedAtLatency.concat([
computedMinLatencyThreshold,
]);
// Determine if we need to reduce the minimum latency we computed
// above based on buffering events that have taken place in the past by
// creating an array of all the buffering events and the above computed
// minimum latency target and averaging all those values.
const minLatencyThreshold =
targetLatencies.reduce((sum, current) => sum + current, 0) /
targetLatencies.length;
// How far away from live edge do we start the compensator.
const maxLatencyThreshold = Math.max(
let maxLatencyThreshold = Math.max(
minLatencyThreshold * 1.4,
Math.min(
segment.duration * 1000 * HIGHEST_LATENCY_SEGMENT_LENGTH_MULTIPLIER,
@ -176,9 +201,17 @@ class LatencyCompensator {
)
);
// If this newly adjusted minimum latency ends up being greater than
// the previously computed maximum latency then reset the maximum
// value using the minimum + an offset.
if (minLatencyThreshold >= maxLatencyThreshold) {
maxLatencyThreshold = minLatencyThreshold + 3000;
}
const segmentTime = segment.dateTimeObject.getTime();
const now = new Date().getTime() + this.clockSkewMs;
const latency = now - segmentTime;
this.currentLatency = latency;
// Since the calculation of latency is based on clock times, it's possible
// things can be reported incorrectly. So we use a sanity check here to
@ -201,7 +234,7 @@ class LatencyCompensator {
) {
const jumpAmount = latency / 1000 - segment.duration * 3;
const seekPosition = this.player.currentTime() + jumpAmount;
console.log(
console.info(
'latency',
latency / 1000,
'jumping',
@ -251,7 +284,7 @@ class LatencyCompensator {
this.stop();
}
console.log(
console.info(
'latency',
latency / 1000,
'min',
@ -275,6 +308,12 @@ class LatencyCompensator {
}
shouldJumpToLive() {
// If we've been rebuffering some recently then don't make it worse by
// jumping more into the future.
if (this.bufferingCounter > 1) {
return false;
}
const now = new Date().getTime();
const delta = now - this.lastJumpOccurred;
return delta > MAX_JUMP_FREQUENCY;
@ -286,7 +325,7 @@ class LatencyCompensator {
this.lastJumpOccurred = new Date();
console.log(
console.info(
'current time',
this.player.currentTime(),
'seeking to',
@ -340,10 +379,6 @@ class LatencyCompensator {
}
timeout() {
if (this.inTimeout) {
return;
}
if (this.jumpingToLiveIgnoreBuffer) {
return;
}
@ -363,6 +398,9 @@ class LatencyCompensator {
}
handlePlaying() {
const wasPreviouslyPlaying = this.playing;
this.playing = true;
clearTimeout(this.bufferingTimer);
if (!this.enabled) {
return;
@ -372,12 +410,22 @@ class LatencyCompensator {
return;
}
// Seek to live immediately on starting playback to handle any long-pause
// If we were not previously playing (was paused, or this is a cold start)
// seek to live immediately on starting playback to handle any long-pause
// scenarios or somebody starting far back from the live edge.
// If we were playing previously then that means we're probably coming back
// from a rebuffering event, meaning we should not be adding more seeking
// to the mix, just let it play.
if (!wasPreviouslyPlaying) {
this.jumpingToLiveIgnoreBuffer = true;
this.player.liveTracker.seekToLiveEdge();
this.lastJumpOccurred = new Date();
}
}
handlePause() {
this.playing = false;
}
handleEnded() {
if (!this.enabled) {
@ -392,19 +440,25 @@ class LatencyCompensator {
return;
}
console.log('handle error', e);
this.timeout();
}
countBufferingEvent() {
this.bufferingCounter++;
if (this.bufferingCounter > REBUFFER_EVENT_LIMIT) {
this.disable();
return;
}
console.log('timeout due to buffering');
this.timeout();
this.bufferedAtLatency.push(this.currentLatency);
console.log(
'latency compensation timeout due to buffering:',
this.bufferingCounter,
'buffering events of',
REBUFFER_EVENT_LIMIT
);
// Allow us to forget about old buffering events if enough time goes by.
setTimeout(() => {
@ -415,7 +469,7 @@ class LatencyCompensator {
}
handleBuffering() {
if (!this.enabled) {
if (!this.enabled || this.inTimeout) {
return;
}
@ -424,6 +478,9 @@ class LatencyCompensator {
return;
}
this.timeout();
clearTimeout(this.bufferingTimer);
this.bufferingTimer = setTimeout(() => {
this.countBufferingEvent();
}, MIN_BUFFER_DURATION);

View File

@ -1,5 +1,5 @@
{
"name": "App",
"name": "Owncast",
"icons": [
{
"src": "\/img\/favicon\/android-icon-36x36.png",
@ -37,5 +37,6 @@
"type": "image\/png",
"density": "4.0"
}
]
],
"display": "fullscreen"
}