mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
Merge branch 'develop' of github.com:varungujarathi9/owncast into develop
This commit is contained in:
commit
7f7a1a2be1
@ -7,7 +7,7 @@ A collection of design contribution guidelines and resources for the Owncast int
|
||||
|
||||
## 👋 Welcome
|
||||
|
||||
Owncast is a is a live streaming and chat server targeted to anybody who has live streaming needs. This means anybody from corporate events, government meetings, game streamers, musicians, churches, TV stations, and more.
|
||||
Owncast is a live streaming and chat server targeted to anybody who has live streaming needs. This means anybody from corporate events, government meetings, game streamers, musicians, churches, TV stations, and more.
|
||||
|
||||
Read the detailed [product definition](https://github.com/owncast/owncast/blob/develop/docs/product-definition.md) to learn more.
|
||||
|
||||
@ -25,7 +25,7 @@ Read the detailed [product definition](https://github.com/owncast/owncast/blob/d
|
||||
|
||||
## 🎭 Target audience
|
||||
|
||||
Owncast is a is a live streaming and chat server targeted to anybody who has live streaming needs. This means anything from corporate events, government meetings, game streams, concerts, TV stations, and more.
|
||||
Owncast is a live streaming and chat server targeted to anybody who has live streaming needs. This means anything from corporate events, government meetings, game streams, concerts, TV stations, and more.
|
||||
|
||||
## 🧑🎨 Product design opportunities
|
||||
|
||||
@ -57,7 +57,7 @@ https://owncast.online/components/?path=%2Fdocs%2Fowncast-styles-colors-componen
|
||||
### Design Files, Screenshots, etc
|
||||
|
||||
We do not currently have any design files that fully represent the state of
|
||||
the Owncast interface. However going forward it would be nice to resolve this
|
||||
the Owncast interface. However, going forward it would be nice to resolve this
|
||||
and collaborate on designs.
|
||||
|
||||
We do have a [PenPot organization](https://design.penpot.app/#/dashboard/team/8373f780-f255-11ec-b774-f940e3befd53/projects). Please ask for access.
|
||||
|
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@0917427245f534bf3543b3a25a7ccf7efcb1bcbe
|
||||
uses: peter-evans/create-or-update-comment@9bb5d837b91928730a318c22b99b9f42a0f005e1
|
||||
with:
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
|
@ -35,7 +35,7 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Run API tests
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: 3
|
||||
|
10
.github/workflows/browser-testing.yml
vendored
10
.github/workflows/browser-testing.yml
vendored
@ -24,10 +24,10 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18.9.0
|
||||
node-version: latest
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-browser-tests
|
||||
with:
|
||||
@ -38,16 +38,16 @@ jobs:
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Install Google Chrome
|
||||
run: sudo apt-get update && sudo apt-get install google-chrome-stable
|
||||
|
||||
- name: Run Browser tests
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 20
|
||||
max_attempts: 3
|
||||
|
4
.github/workflows/build-storybook.yml
vendored
4
.github/workflows/build-storybook.yml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-bundle-web-app
|
||||
with:
|
||||
@ -47,7 +47,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Dispatch event to web site
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.BUNDLE_STORYBOOK_OWNCAST_ONLINE }}
|
||||
repository: owncast/owncast.github.io
|
||||
|
2
.github/workflows/chromatic.yml
vendored
2
.github/workflows/chromatic.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
||||
- name: Publish to Chromatic
|
||||
if: ${{ github.actor != 'renovate[bot]' && github.actor != 'renovate' }}
|
||||
|
||||
uses: chromaui/action@v1
|
||||
uses: chromaui/action@v11
|
||||
# Chromatic GitHub Action options
|
||||
with:
|
||||
workingDir: web
|
||||
|
65
.github/workflows/codeql-analysis.yml
vendored
65
.github/workflows/codeql-analysis.yml
vendored
@ -9,16 +9,16 @@
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
name: 'CodeQL'
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ develop ]
|
||||
branches: [develop]
|
||||
paths-ignore:
|
||||
- 'static/**'
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ develop ]
|
||||
branches: [develop]
|
||||
paths-ignore:
|
||||
- 'static/**'
|
||||
|
||||
@ -30,41 +30,46 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go', 'javascript' ]
|
||||
language: ['go', 'javascript']
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/${{ matrix.language }}.yml
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
config-file: ./.github/codeql/${{ matrix.language }}.yml
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
2
.github/workflows/container.yaml
vendored
2
.github/workflows/container.yaml
vendored
@ -49,7 +49,7 @@ jobs:
|
||||
EARTHLY_BUILD_TAG: 'nightly'
|
||||
EARTHLY_BUILD_BRANCH: 'develop'
|
||||
EARTHLY_PUSH: true
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 20
|
||||
max_attempts: 3
|
||||
|
@ -2,26 +2,26 @@ name: javascript-packages
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- openapi.yaml
|
||||
- spec/openapi.yaml
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Generate API Documentation
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run redoc on openapi.yaml
|
||||
run: |
|
||||
npx redoc-cli bundle openapi.yaml -o docs/api/index.html --options '{"hideHostname": true, "pathInMiddlePanel": true}'
|
||||
- name: Run redoc on openapi.yaml
|
||||
run: |
|
||||
npx redoc-cli bundle spec/openapi.yaml -o docs/api/index.html --options '{"hideHostname": true, "pathInMiddlePanel": true}'
|
||||
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
author_name: Owncast
|
||||
author_email: owncast@owncast.online
|
||||
message: "Commit updated API documentation"
|
||||
add: "docs/api/index.html"
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Commit changes
|
||||
uses: EndBug/add-and-commit@v9
|
||||
with:
|
||||
author_name: Owncast
|
||||
author_email: owncast@owncast.online
|
||||
message: 'Commit updated API documentation'
|
||||
add: 'docs/api/index.html'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
6
.github/workflows/go-lint.yml
vendored
6
.github/workflows/go-lint.yml
vendored
@ -26,13 +26,13 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
- uses: actions/checkout@v4
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
only-new-issues: true
|
||||
args: --timeout=3m
|
||||
|
10
.github/workflows/go-tests.yaml
vendored
10
.github/workflows/go-tests.yaml
vendored
@ -12,13 +12,13 @@ jobs:
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.20.x, 1.21.x]
|
||||
go-version: [1.21.x, 1.22.x]
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
@ -28,7 +28,7 @@ jobs:
|
||||
go-test-
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1'
|
||||
cache: true
|
||||
@ -49,7 +49,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
@ -59,7 +59,7 @@ jobs:
|
||||
go-test-
|
||||
|
||||
- name: Install go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1'
|
||||
cache: true
|
||||
|
10
.github/workflows/hls-tests.yml
vendored
10
.github/workflows/hls-tests.yml
vendored
@ -25,13 +25,13 @@ jobs:
|
||||
with:
|
||||
concurrent_skipping: 'same_content_newer'
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-hls-tests
|
||||
with:
|
||||
@ -43,14 +43,14 @@ jobs:
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Local stroage
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: 3
|
||||
command: cd test/automated/hls && ./run.sh
|
||||
|
||||
- name: S3 storage
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: 3
|
||||
|
12
.github/workflows/javascript-format-build.yml
vendored
12
.github/workflows/javascript-format-build.yml
vendored
@ -39,7 +39,7 @@ jobs:
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files-yaml
|
||||
uses: tj-actions/changed-files@v40
|
||||
uses: tj-actions/changed-files@v44
|
||||
with:
|
||||
path: 'web'
|
||||
files_ignore: |
|
||||
@ -50,7 +50,7 @@ jobs:
|
||||
- '**/*.{js,ts,tsx,jsx,css,md}'
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-bundle-web-app
|
||||
with:
|
||||
@ -72,6 +72,9 @@ jobs:
|
||||
if: steps.changed-files-yaml.outputs.src_any_changed == 'true'
|
||||
run: npx prettier --write ${{ steps.changed-files-yaml.outputs.src_all_changed_files }}
|
||||
|
||||
- name: Debug changed files output
|
||||
run: 'pwd && echo "Changed files: ${{ steps.changed-files-yaml.outputs.src_all_changed_files }}"'
|
||||
|
||||
- name: Commit changes
|
||||
if: steps.changed-files-yaml.outputs.src_any_changed == 'true'
|
||||
uses: EndBug/add-and-commit@v9
|
||||
@ -80,6 +83,7 @@ jobs:
|
||||
author_email: owncast@owncast.online
|
||||
message: 'Javascript formatting autofixes'
|
||||
add: ${{ steps.changed-files-yaml.outputs.src_all_changed_files }}
|
||||
cwd: './web' # Ensure this is the correct relative directory
|
||||
pull: '--rebase --autostash'
|
||||
|
||||
unused-code:
|
||||
@ -106,7 +110,7 @@ jobs:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-bundle-web-app
|
||||
with:
|
||||
@ -140,7 +144,7 @@ jobs:
|
||||
skip_after_successful_duplicate: 'true'
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-bundle-web-app
|
||||
with:
|
||||
|
2
.github/workflows/javascript-tests.yml
vendored
2
.github/workflows/javascript-tests.yml
vendored
@ -25,7 +25,7 @@ jobs:
|
||||
node-version: 18.9.0
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-javascript-tests
|
||||
with:
|
||||
|
10
.github/workflows/screenshots.yml
vendored
10
.github/workflows/screenshots.yml
vendored
@ -15,13 +15,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.22'
|
||||
cache: true
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules-screenshots
|
||||
with:
|
||||
@ -33,7 +33,7 @@ jobs:
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Automate screenshots
|
||||
uses: nick-fields/retry@v2
|
||||
uses: nick-fields/retry@v3
|
||||
with:
|
||||
timeout_minutes: 10
|
||||
max_attempts: 4
|
||||
@ -51,7 +51,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Dispatch event to web site
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.BUNDLE_STORYBOOK_OWNCAST_ONLINE }}
|
||||
repository: owncast/owncast.github.io
|
||||
|
2
.github/workflows/shellcheck.yml
vendored
2
.github/workflows/shellcheck.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
||||
env:
|
||||
LANG: C.UTF-8
|
||||
container:
|
||||
image: docker.io/ubuntu:23.10
|
||||
image: docker.io/ubuntu:24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
@ -5,7 +5,7 @@ run:
|
||||
# Define the Go version limit.
|
||||
# Mainly related to generics support in go1.18.
|
||||
# Default: use Go version from the go.mod file, fallback on the env var `GOVERSION`, fallback on 1.18
|
||||
go: '1.21'
|
||||
go: '1.22'
|
||||
|
||||
issues:
|
||||
# The linter has a default list of ignorable errors. Turning this on will enable that list.
|
||||
@ -69,7 +69,7 @@ linters-settings:
|
||||
|
||||
gosimple:
|
||||
# Select the Go version to target. The default is '1.13'.
|
||||
go: '1.21'
|
||||
go: '1.22'
|
||||
# https://staticcheck.io/docs/options#checks
|
||||
checks: ['all']
|
||||
|
||||
|
@ -22,7 +22,7 @@ ENV NAME=${NAME}
|
||||
RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -ldflags "-extldflags \"-static\" -s -w -X github.com/owncast/owncast/config.GitCommit=$GIT_COMMIT -X github.com/owncast/owncast/config.VersionNumber=$VERSION -X github.com/owncast/owncast/config.BuildPlatform=$NAME" -o owncast .
|
||||
|
||||
# Create the image by copying the result of the build into a new alpine image
|
||||
FROM alpine:3.18.4
|
||||
FROM alpine:3.20.0
|
||||
RUN apk update && apk add --no-cache ffmpeg ffmpeg-libs ca-certificates && update-ca-certificates
|
||||
|
||||
RUN addgroup -g 101 -S owncast && adduser -u 101 -S owncast -G owncast
|
||||
|
93
README.md
93
README.md
@ -1,37 +1,48 @@
|
||||
<br />
|
||||
<p align="center">
|
||||
<a href="https://github.com/owncast/owncast" alt="Owncast">
|
||||
<img src="https://owncast.online/images/logo.png" alt="Logo" width="200">
|
||||
<img src="https://owncast.online/images/logo.png" alt="Owncast Logo" width="200">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>Take control over your content and stream it yourself.</strong>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/owncast/owncast/blob/develop/LICENSE">
|
||||
<img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br/>
|
||||
|
||||
<p align="center">
|
||||
<strong>Take control over your content and stream it yourself.</strong>
|
||||
<br />
|
||||
<a href="https://owncast.online"><strong>Explore the docs »</strong></a>
|
||||
<br />
|
||||
<a href="https://watch.owncast.online/">View Demo</a>
|
||||
·
|
||||
<a href="https://broadcast.owncast.online/">Use Our Server for Testing</a>
|
||||
·
|
||||
<a href="https://owncast.online/faq/">FAQ</a>
|
||||
·
|
||||
<a href="https://github.com/owncast/owncast/issues">Report Bug</a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://owncast.online"><strong>Explore the docs »</strong></a>
|
||||
<br />
|
||||
<a href="https://watch.owncast.online/">View Demo</a>
|
||||
·
|
||||
<a href="https://owncast.online/faq/">FAQ</a>
|
||||
·
|
||||
<a href="https://github.com/owncast/owncast/issues">Report Bug</a>
|
||||
</p>
|
||||
|
||||
|
||||
<!-- TABLE OF CONTENTS -->
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [About the Project](#about-the-project)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Use with your broadcasting software](#use-with-your-existing-broadcasting-software)
|
||||
- [Building from source](#building-from-source)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
- 📒 [About the Project](#about-the-project)
|
||||
- 🚀 [Getting Started](#getting-started)
|
||||
- 👨💻 [Use with your broadcasting software](#use-with-your-existing-broadcasting-software)
|
||||
- 🛠 [Building from source](#building-from-source)
|
||||
- 🚨 [Important note about source code and the develop branch](#important-note-about-source-code-and-the-develop-branch)
|
||||
- 🗄️ [Backend](#backend)
|
||||
- ⚛️ [Frontend](#frontend)
|
||||
- 👏 [Contributing](#contributing)
|
||||
- 💵 [Donors](#donors)
|
||||
- 📝 [License](#license)
|
||||
- [Contact](#contact)
|
||||
|
||||
<!-- ABOUT THE PROJECT -->
|
||||
@ -95,7 +106,7 @@ The Owncast backend is a service written in Go.
|
||||
1. Ensure you have prerequisites installed.
|
||||
- C compiler, such as [GCC compiler](https://gcc.gnu.org/install/download.html) or a [Musl-compatible compiler](https://musl.libc.org/)
|
||||
- [ffmpeg](https://ffmpeg.org/download.html)
|
||||
1. Install the [Go toolchain](https://golang.org/dl/) (1.21 or above).
|
||||
1. Install the [Go toolchain](https://golang.org/dl/) (1.22 or above).
|
||||
1. Clone the repo. `git clone https://github.com/owncast/owncast`
|
||||
1. `go run main.go` will run from the source.
|
||||
1. Visit `http://yourserver:8080` to access the web interface or `http://yourserver:8080/admin` to access the admin.
|
||||
@ -117,18 +128,50 @@ And while we have a small team of kind, talented and thoughtful volunteers, we h
|
||||
We abide by our [Code of Conduct](https://owncast.online/contribute/) and feel strongly about open, appreciative, and empathetic people joining us.
|
||||
We’ve been very lucky to have this so far, so maybe you can help us with your skills and passion, too!
|
||||
|
||||
If you're new to the project, maybe you'd be interested in looking at [](https://github.com/owncast/owncast/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22).
|
||||
|
||||
There is a larger, more detailed, and more up-to-date [guide for helping contribute to Owncast on our website](https://owncast.online/help/).
|
||||
|
||||
### Donors
|
||||
The Owncast project is possible thanks to the people who make a donation to support us and our work.
|
||||
Thank you to all our donors who help keep Owncast running by donating on OpenCollective. You can support this project by [becoming a backer/sponsor](https://opencollective.com/owncast#suppor).
|
||||
|
||||
<div>
|
||||
<a href="https://opencollective.com/owncast#support">
|
||||
<img alt="GitHub issues by-label" src="https://opencollective.com/owncast/tiers/backers.svg?avatarHeight=36&width=600" alt="Backer button">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- LICENSE -->
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the MIT License. See `LICENSE` for more information.
|
||||
|
||||
## Supported by
|
||||
|
||||
- This project is tested with [BrowserStack](https://browserstack.com).
|
||||
## Support
|
||||
|
||||
<ul style="font-size:21px; color:black; ">
|
||||
<li>Browser testing via <a
|
||||
href="https://www.lambdatest.com/" target="_blank"><img
|
||||
src="https://www.lambdatest.com/support/img/logo.svg"
|
||||
style="vertical-align: middle;margin-left:5px" width="147" height="26"
|
||||
/></a></li>
|
||||
<li>Project chat provided by
|
||||
<a href="https://rocket.chat" target="_blank">
|
||||
<img src="https://owncast.online/images/sponsors/rocketchat.png" width="147" height="26" style="vertical-align: middle;margin-left:5px">
|
||||
</a>
|
||||
</li>
|
||||
<li>CDN services by
|
||||
<a href="https://fastly.com" target="_blank">
|
||||
<img src="https://owncast.online/images/sponsors/fastly.png" height="26" style="vertical-align: middle;margin-left:5px">
|
||||
</a>
|
||||
</li>
|
||||
<li>UI testing with Chromatic
|
||||
<a href="https://chromatic.com" target="_blank">
|
||||
<img src="https://owncast.online/images/sponsors/chromatic.png" height="26" style="vertical-align: middle;margin-left:5px">
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- CONTACT -->
|
||||
|
||||
## Contact
|
||||
|
@ -17,7 +17,6 @@ func Start(datastore *data.Datastore) {
|
||||
persistence.Setup(datastore)
|
||||
workerpool.InitOutboundWorkerPool()
|
||||
inbox.InitInboxWorkerPool()
|
||||
StartRouter()
|
||||
|
||||
// Generate the keys for signing federated activity if needed.
|
||||
if data.GetPrivateKey() == "" {
|
||||
|
36
activitypub/persistence/followers_fixture.go
Normal file
36
activitypub/persistence/followers_fixture.go
Normal file
@ -0,0 +1,36 @@
|
||||
//go:build fixture
|
||||
// +build fixture
|
||||
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/owncast/owncast/models"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func addFollowersFixtureData() {
|
||||
log.Println("Adding followers fixture data...")
|
||||
file, err := os.Open("./test/fixture/followers_fixture.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error opening file:", err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var followers []models.Follower
|
||||
decoder := json.NewDecoder(file)
|
||||
err = decoder.Decode(&followers)
|
||||
if err != nil {
|
||||
fmt.Println("Error decoding JSON:", err)
|
||||
return
|
||||
}
|
||||
|
||||
// Iterate over the followers array
|
||||
for _, follower := range followers {
|
||||
createFollow(follower.ActorIRI, follower.Inbox, "", follower.Name, follower.Username, follower.Image, nil, true)
|
||||
}
|
||||
}
|
8
activitypub/persistence/followers_nofixture.go
Normal file
8
activitypub/persistence/followers_nofixture.go
Normal file
@ -0,0 +1,8 @@
|
||||
//go:build !fixture
|
||||
// +build !fixture
|
||||
|
||||
package persistence
|
||||
|
||||
func addFollowersFixtureData() {
|
||||
// no-op
|
||||
}
|
@ -27,6 +27,7 @@ func Setup(datastore *data.Datastore) {
|
||||
createFederationFollowersTable()
|
||||
createFederationOutboxTable()
|
||||
createFederatedActivitiesTable()
|
||||
addFollowersFixtureData()
|
||||
}
|
||||
|
||||
// AddFollow will save a follow to the datastore.
|
||||
|
@ -1,35 +0,0 @@
|
||||
package activitypub
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/activitypub/controllers"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
)
|
||||
|
||||
// StartRouter will start the federation specific http router.
|
||||
func StartRouter() {
|
||||
// WebFinger
|
||||
http.HandleFunc("/.well-known/webfinger", controllers.WebfingerHandler)
|
||||
|
||||
// Host Metadata
|
||||
http.HandleFunc("/.well-known/host-meta", controllers.HostMetaController)
|
||||
|
||||
// Nodeinfo v1
|
||||
http.HandleFunc("/.well-known/nodeinfo", controllers.NodeInfoController)
|
||||
|
||||
// x-nodeinfo v2
|
||||
http.HandleFunc("/.well-known/x-nodeinfo2", controllers.XNodeInfo2Controller)
|
||||
|
||||
// Nodeinfo v2
|
||||
http.HandleFunc("/nodeinfo/2.0", controllers.NodeInfoV2Controller)
|
||||
|
||||
// Instance details
|
||||
http.HandleFunc("/api/v1/instance", controllers.InstanceV1Controller)
|
||||
|
||||
// Single ActivityPub Actor
|
||||
http.HandleFunc("/federation/user/", middleware.RequireActivityPubOrRedirect(controllers.ActorHandler))
|
||||
|
||||
// Single AP object
|
||||
http.HandleFunc("/federation/", middleware.RequireActivityPubOrRedirect(controllers.ObjectHandler))
|
||||
}
|
@ -4,7 +4,7 @@ import "path/filepath"
|
||||
|
||||
const (
|
||||
// StaticVersionNumber is the version of Owncast that is used when it's not overwritten via build-time settings.
|
||||
StaticVersionNumber = "0.1.3" // Shown when you build from develop
|
||||
StaticVersionNumber = "0.2.0" // Shown when you build from develop
|
||||
// FfmpegSuggestedVersion is the version of ffmpeg we suggest.
|
||||
FfmpegSuggestedVersion = "v4.1.5" // Requires the v
|
||||
// DataDirectory is the directory we save data to.
|
||||
|
@ -261,7 +261,7 @@ func SendSystemMessage(integration user.ExternalAPIUser, w http.ResponseWriter,
|
||||
// SendSystemMessageToConnectedClient will handle incoming requests to send a single message to a single connected client by ID.
|
||||
func SendSystemMessageToConnectedClient(integration user.ExternalAPIUser, w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
clientIDText, err := utils.ReadRestURLParameter(r, "clientId")
|
||||
clientIDText, err := utils.GetURLParam(r, "clientId")
|
||||
if err != nil {
|
||||
controllers.BadRequestHandler(w, err)
|
||||
return
|
||||
|
@ -802,6 +802,42 @@ func SetVideoServingEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.WriteSimpleResponse(w, true, "custom video serving endpoint updated")
|
||||
}
|
||||
|
||||
// SetChatSpamProtectionEnabled will enable or disable the chat spam protection.
|
||||
func SetChatSpamProtectionEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
if !requirePOST(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
configValue, success := getValueFromRequest(w, r)
|
||||
if !success {
|
||||
return
|
||||
}
|
||||
|
||||
if err := data.SetChatSpamProtectionEnabled(configValue.Value.(bool)); err != nil {
|
||||
controllers.WriteSimpleResponse(w, false, err.Error())
|
||||
return
|
||||
}
|
||||
controllers.WriteSimpleResponse(w, true, "chat spam protection changed")
|
||||
}
|
||||
|
||||
// SetChatSlurFilterEnabled will enable or disable the chat slur filter.
|
||||
func SetChatSlurFilterEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
if !requirePOST(w, r) {
|
||||
return
|
||||
}
|
||||
|
||||
configValue, success := getValueFromRequest(w, r)
|
||||
if !success {
|
||||
return
|
||||
}
|
||||
|
||||
if err := data.SetChatSlurFilterEnabled(configValue.Value.(bool)); err != nil {
|
||||
controllers.WriteSimpleResponse(w, false, err.Error())
|
||||
return
|
||||
}
|
||||
controllers.WriteSimpleResponse(w, true, "chat message slur filter changed")
|
||||
}
|
||||
|
||||
func requirePOST(w http.ResponseWriter, r *http.Request) bool {
|
||||
if r.Method != controllers.POST {
|
||||
controllers.WriteSimpleResponse(w, false, r.Method+" not supported")
|
||||
|
@ -76,9 +76,13 @@ func DeleteCustomEmoji(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// var emojiFileName = filepath.Base(emoji.Name)
|
||||
targetPath := filepath.Join(config.CustomEmojiPath, emoji.Name)
|
||||
|
||||
if !filepath.IsLocal(targetPath) {
|
||||
controllers.WriteSimpleResponse(w, false, "Emoji path is not valid")
|
||||
return
|
||||
}
|
||||
|
||||
if err := os.Remove(targetPath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
controllers.WriteSimpleResponse(w, false, fmt.Sprintf("Emoji %q doesn't exist", emoji.Name))
|
||||
|
@ -49,20 +49,22 @@ func GetServerConfig(w http.ResponseWriter, r *http.Request) {
|
||||
CustomJavascript: data.GetCustomJavascript(),
|
||||
AppearanceVariables: data.GetCustomColorVariableValues(),
|
||||
},
|
||||
FFmpegPath: ffmpeg,
|
||||
AdminPassword: data.GetAdminPassword(),
|
||||
StreamKeys: data.GetStreamKeys(),
|
||||
StreamKeyOverridden: config.TemporaryStreamKey != "",
|
||||
WebServerPort: config.WebServerPort,
|
||||
WebServerIP: config.WebServerIP,
|
||||
RTMPServerPort: data.GetRTMPPortNumber(),
|
||||
ChatDisabled: data.GetChatDisabled(),
|
||||
ChatJoinMessagesEnabled: data.GetChatJoinPartMessagesEnabled(),
|
||||
SocketHostOverride: data.GetWebsocketOverrideHost(),
|
||||
VideoServingEndpoint: data.GetVideoServingEndpoint(),
|
||||
ChatEstablishedUserMode: data.GetChatEstbalishedUsersOnlyMode(),
|
||||
HideViewerCount: data.GetHideViewerCount(),
|
||||
DisableSearchIndexing: data.GetDisableSearchIndexing(),
|
||||
FFmpegPath: ffmpeg,
|
||||
AdminPassword: data.GetAdminPassword(),
|
||||
StreamKeys: data.GetStreamKeys(),
|
||||
StreamKeyOverridden: config.TemporaryStreamKey != "",
|
||||
WebServerPort: config.WebServerPort,
|
||||
WebServerIP: config.WebServerIP,
|
||||
RTMPServerPort: data.GetRTMPPortNumber(),
|
||||
ChatDisabled: data.GetChatDisabled(),
|
||||
ChatJoinMessagesEnabled: data.GetChatJoinPartMessagesEnabled(),
|
||||
SocketHostOverride: data.GetWebsocketOverrideHost(),
|
||||
VideoServingEndpoint: data.GetVideoServingEndpoint(),
|
||||
ChatEstablishedUserMode: data.GetChatEstbalishedUsersOnlyMode(),
|
||||
ChatSpamProtectionEnabled: data.GetChatSpamProtectionEnabled(),
|
||||
ChatSlurFilterEnabled: data.GetChatSlurFilterEnabled(),
|
||||
HideViewerCount: data.GetHideViewerCount(),
|
||||
DisableSearchIndexing: data.GetDisableSearchIndexing(),
|
||||
VideoSettings: videoSettings{
|
||||
VideoQualityVariants: videoQualityVariants,
|
||||
LatencyLevel: data.GetStreamLatencyLevel().Level,
|
||||
@ -100,31 +102,33 @@ func GetServerConfig(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
type serverConfigAdminResponse struct {
|
||||
InstanceDetails webConfigResponse `json:"instanceDetails"`
|
||||
Notifications notificationsConfigResponse `json:"notifications"`
|
||||
YP yp `json:"yp"`
|
||||
FFmpegPath string `json:"ffmpegPath"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
SocketHostOverride string `json:"socketHostOverride,omitempty"`
|
||||
WebServerIP string `json:"webServerIP"`
|
||||
VideoCodec string `json:"videoCodec"`
|
||||
VideoServingEndpoint string `json:"videoServingEndpoint"`
|
||||
S3 models.S3 `json:"s3"`
|
||||
Federation federationConfigResponse `json:"federation"`
|
||||
SupportedCodecs []string `json:"supportedCodecs"`
|
||||
ExternalActions []models.ExternalAction `json:"externalActions"`
|
||||
ForbiddenUsernames []string `json:"forbiddenUsernames"`
|
||||
SuggestedUsernames []string `json:"suggestedUsernames"`
|
||||
StreamKeys []models.StreamKey `json:"streamKeys"`
|
||||
VideoSettings videoSettings `json:"videoSettings"`
|
||||
RTMPServerPort int `json:"rtmpServerPort"`
|
||||
WebServerPort int `json:"webServerPort"`
|
||||
ChatDisabled bool `json:"chatDisabled"`
|
||||
ChatJoinMessagesEnabled bool `json:"chatJoinMessagesEnabled"`
|
||||
ChatEstablishedUserMode bool `json:"chatEstablishedUserMode"`
|
||||
DisableSearchIndexing bool `json:"disableSearchIndexing"`
|
||||
StreamKeyOverridden bool `json:"streamKeyOverridden"`
|
||||
HideViewerCount bool `json:"hideViewerCount"`
|
||||
InstanceDetails webConfigResponse `json:"instanceDetails"`
|
||||
Notifications notificationsConfigResponse `json:"notifications"`
|
||||
YP yp `json:"yp"`
|
||||
FFmpegPath string `json:"ffmpegPath"`
|
||||
AdminPassword string `json:"adminPassword"`
|
||||
SocketHostOverride string `json:"socketHostOverride,omitempty"`
|
||||
WebServerIP string `json:"webServerIP"`
|
||||
VideoCodec string `json:"videoCodec"`
|
||||
VideoServingEndpoint string `json:"videoServingEndpoint"`
|
||||
S3 models.S3 `json:"s3"`
|
||||
Federation federationConfigResponse `json:"federation"`
|
||||
SupportedCodecs []string `json:"supportedCodecs"`
|
||||
ExternalActions []models.ExternalAction `json:"externalActions"`
|
||||
ForbiddenUsernames []string `json:"forbiddenUsernames"`
|
||||
SuggestedUsernames []string `json:"suggestedUsernames"`
|
||||
StreamKeys []models.StreamKey `json:"streamKeys"`
|
||||
VideoSettings videoSettings `json:"videoSettings"`
|
||||
RTMPServerPort int `json:"rtmpServerPort"`
|
||||
WebServerPort int `json:"webServerPort"`
|
||||
ChatDisabled bool `json:"chatDisabled"`
|
||||
ChatJoinMessagesEnabled bool `json:"chatJoinMessagesEnabled"`
|
||||
ChatEstablishedUserMode bool `json:"chatEstablishedUserMode"`
|
||||
ChatSpamProtectionEnabled bool `json:"chatSpamProtectionEnabled"`
|
||||
ChatSlurFilterEnabled bool `json:"chatSlurFilterEnabled"`
|
||||
DisableSearchIndexing bool `json:"disableSearchIndexing"`
|
||||
StreamKeyOverridden bool `json:"streamKeyOverridden"`
|
||||
HideViewerCount bool `json:"hideViewerCount"`
|
||||
}
|
||||
|
||||
type videoSettings struct {
|
||||
|
@ -39,7 +39,7 @@ func RegisterFediverseOTPRequest(u user.User, w http.ResponseWriter, r *http.Req
|
||||
return
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf("<p>This is an automated message from %s. If you did not request this message please ignore or block. Your requested one-time code is:</p><p>%s</p>", data.GetServerName(), reg.Code)
|
||||
msg := fmt.Sprintf("<p>One-time code from %s: %s. If you did not request this message please ignore or block.</p>", data.GetServerName(), reg.Code)
|
||||
if err := activitypub.SendDirectFederatedMessage(msg, reg.Account); err != nil {
|
||||
controllers.WriteSimpleResponse(w, false, "Could not send code to fediverse: "+err.Error())
|
||||
return
|
||||
|
@ -13,18 +13,18 @@ import (
|
||||
func HandleAuthEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method == http.MethodGet {
|
||||
// Require the GET request for IndieAuth to be behind admin login.
|
||||
f := middleware.RequireAdminAuth(handleAuthEndpointGet)
|
||||
f := middleware.RequireAdminAuth(HandleAuthEndpointGet)
|
||||
f(w, r)
|
||||
return
|
||||
} else if r.Method == http.MethodPost {
|
||||
handleAuthEndpointPost(w, r)
|
||||
HandleAuthEndpointPost(w, r)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func handleAuthEndpointGet(w http.ResponseWriter, r *http.Request) {
|
||||
func HandleAuthEndpointGet(w http.ResponseWriter, r *http.Request) {
|
||||
clientID := r.URL.Query().Get("client_id")
|
||||
redirectURI := r.URL.Query().Get("redirect_uri")
|
||||
codeChallenge := r.URL.Query().Get("code_challenge")
|
||||
@ -57,7 +57,7 @@ func handleAuthEndpointGet(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
|
||||
}
|
||||
|
||||
func handleAuthEndpointPost(w http.ResponseWriter, r *http.Request) {
|
||||
func HandleAuthEndpointPost(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
controllers.WriteSimpleResponse(w, false, err.Error())
|
||||
return
|
||||
|
@ -16,26 +16,27 @@ import (
|
||||
)
|
||||
|
||||
type webConfigResponse struct {
|
||||
AppearanceVariables map[string]string `json:"appearanceVariables"`
|
||||
Name string `json:"name"`
|
||||
CustomStyles string `json:"customStyles"`
|
||||
StreamTitle string `json:"streamTitle,omitempty"` // What's going on with the current stream
|
||||
OfflineMessage string `json:"offlineMessage"`
|
||||
Logo string `json:"logo"`
|
||||
Version string `json:"version"`
|
||||
SocketHostOverride string `json:"socketHostOverride,omitempty"`
|
||||
ExtraPageContent string `json:"extraPageContent"`
|
||||
Summary string `json:"summary"`
|
||||
Tags []string `json:"tags"`
|
||||
SocialHandles []models.SocialHandle `json:"socialHandles"`
|
||||
ExternalActions []models.ExternalAction `json:"externalActions"`
|
||||
Notifications notificationsConfigResponse `json:"notifications"`
|
||||
Federation federationConfigResponse `json:"federation"`
|
||||
MaxSocketPayloadSize int `json:"maxSocketPayloadSize"`
|
||||
HideViewerCount bool `json:"hideViewerCount"`
|
||||
ChatDisabled bool `json:"chatDisabled"`
|
||||
NSFW bool `json:"nsfw"`
|
||||
Authentication authenticationConfigResponse `json:"authentication"`
|
||||
AppearanceVariables map[string]string `json:"appearanceVariables"`
|
||||
Name string `json:"name"`
|
||||
CustomStyles string `json:"customStyles"`
|
||||
StreamTitle string `json:"streamTitle,omitempty"` // What's going on with the current stream
|
||||
OfflineMessage string `json:"offlineMessage"`
|
||||
Logo string `json:"logo"`
|
||||
Version string `json:"version"`
|
||||
SocketHostOverride string `json:"socketHostOverride,omitempty"`
|
||||
ExtraPageContent string `json:"extraPageContent"`
|
||||
Summary string `json:"summary"`
|
||||
Tags []string `json:"tags"`
|
||||
SocialHandles []models.SocialHandle `json:"socialHandles"`
|
||||
ExternalActions []models.ExternalAction `json:"externalActions"`
|
||||
Notifications notificationsConfigResponse `json:"notifications"`
|
||||
Federation federationConfigResponse `json:"federation"`
|
||||
MaxSocketPayloadSize int `json:"maxSocketPayloadSize"`
|
||||
HideViewerCount bool `json:"hideViewerCount"`
|
||||
ChatDisabled bool `json:"chatDisabled"`
|
||||
ChatSpamProtectionDisabled bool `json:"chatSpamProtectionDisabled"`
|
||||
NSFW bool `json:"nsfw"`
|
||||
Authentication authenticationConfigResponse `json:"authentication"`
|
||||
}
|
||||
|
||||
type federationConfigResponse struct {
|
||||
@ -118,26 +119,27 @@ func getConfigResponse() webConfigResponse {
|
||||
}
|
||||
|
||||
return webConfigResponse{
|
||||
Name: data.GetServerName(),
|
||||
Summary: serverSummary,
|
||||
OfflineMessage: offlineMessage,
|
||||
Logo: "/logo",
|
||||
Tags: data.GetServerMetadataTags(),
|
||||
Version: config.GetReleaseString(),
|
||||
NSFW: data.GetNSFW(),
|
||||
SocketHostOverride: data.GetWebsocketOverrideHost(),
|
||||
ExtraPageContent: pageContent,
|
||||
StreamTitle: data.GetStreamTitle(),
|
||||
SocialHandles: socialHandles,
|
||||
ChatDisabled: data.GetChatDisabled(),
|
||||
ExternalActions: data.GetExternalActions(),
|
||||
CustomStyles: data.GetCustomStyles(),
|
||||
MaxSocketPayloadSize: config.MaxSocketPayloadSize,
|
||||
Federation: federationResponse,
|
||||
Notifications: notificationsResponse,
|
||||
Authentication: authenticationResponse,
|
||||
AppearanceVariables: data.GetCustomColorVariableValues(),
|
||||
HideViewerCount: data.GetHideViewerCount(),
|
||||
Name: data.GetServerName(),
|
||||
Summary: serverSummary,
|
||||
OfflineMessage: offlineMessage,
|
||||
Logo: "/logo",
|
||||
Tags: data.GetServerMetadataTags(),
|
||||
Version: config.GetReleaseString(),
|
||||
NSFW: data.GetNSFW(),
|
||||
SocketHostOverride: data.GetWebsocketOverrideHost(),
|
||||
ExtraPageContent: pageContent,
|
||||
StreamTitle: data.GetStreamTitle(),
|
||||
SocialHandles: socialHandles,
|
||||
ChatDisabled: data.GetChatDisabled(),
|
||||
ChatSpamProtectionDisabled: data.GetChatSpamProtectionEnabled(),
|
||||
ExternalActions: data.GetExternalActions(),
|
||||
CustomStyles: data.GetCustomStyles(),
|
||||
MaxSocketPayloadSize: config.MaxSocketPayloadSize,
|
||||
Federation: federationResponse,
|
||||
Notifications: notificationsResponse,
|
||||
Authentication: authenticationResponse,
|
||||
AppearanceVariables: data.GetCustomColorVariableValues(),
|
||||
HideViewerCount: data.GetHideViewerCount(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
|
||||
// ServeCustomJavascript will serve optional custom Javascript.
|
||||
func ServeCustomJavascript(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/javascript; charset=utf-8")
|
||||
|
||||
js := data.GetCustomJavascript()
|
||||
_, _ = w.Write([]byte(js))
|
||||
}
|
||||
|
@ -3,7 +3,9 @@ package controllers
|
||||
import (
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/utils"
|
||||
)
|
||||
@ -13,16 +15,28 @@ const (
|
||||
contentTypeGIF = "image/gif"
|
||||
)
|
||||
|
||||
var previewThumbCache = ttlcache.New(
|
||||
ttlcache.WithTTL[string, []byte](15),
|
||||
ttlcache.WithCapacity[string, []byte](1),
|
||||
ttlcache.WithDisableTouchOnHit[string, []byte](),
|
||||
)
|
||||
|
||||
// GetThumbnail will return the thumbnail image as a response.
|
||||
func GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
imageFilename := "thumbnail.jpg"
|
||||
imagePath := filepath.Join(config.TempDir, imageFilename)
|
||||
httpCacheTime := utils.GetCacheDurationSecondsForPath(imagePath)
|
||||
inMemoryCacheTime := time.Duration(15) * time.Second
|
||||
|
||||
var imageBytes []byte
|
||||
var err error
|
||||
|
||||
if utils.DoesFileExists(imagePath) {
|
||||
if previewThumbCache.Get(imagePath) != nil {
|
||||
ci := previewThumbCache.Get(imagePath)
|
||||
imageBytes = ci.Value()
|
||||
} else if utils.DoesFileExists(imagePath) {
|
||||
imageBytes, err = getImage(imagePath)
|
||||
previewThumbCache.Set(imagePath, imageBytes, inMemoryCacheTime)
|
||||
} else {
|
||||
GetLogo(w, r)
|
||||
return
|
||||
@ -33,20 +47,25 @@ func GetThumbnail(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
cacheTime := utils.GetCacheDurationSecondsForPath(imagePath)
|
||||
writeBytesAsImage(imageBytes, contentTypeJPEG, w, cacheTime)
|
||||
writeBytesAsImage(imageBytes, contentTypeJPEG, w, httpCacheTime)
|
||||
}
|
||||
|
||||
// GetPreview will return the preview gif as a response.
|
||||
func GetPreview(w http.ResponseWriter, r *http.Request) {
|
||||
imageFilename := "preview.gif"
|
||||
imagePath := filepath.Join(config.TempDir, imageFilename)
|
||||
httpCacheTime := utils.GetCacheDurationSecondsForPath(imagePath)
|
||||
inMemoryCacheTime := time.Duration(15) * time.Second
|
||||
|
||||
var imageBytes []byte
|
||||
var err error
|
||||
|
||||
if utils.DoesFileExists(imagePath) {
|
||||
if previewThumbCache.Get(imagePath) != nil {
|
||||
ci := previewThumbCache.Get(imagePath)
|
||||
imageBytes = ci.Value()
|
||||
} else if utils.DoesFileExists(imagePath) {
|
||||
imageBytes, err = getImage(imagePath)
|
||||
previewThumbCache.Set(imagePath, imageBytes, inMemoryCacheTime)
|
||||
} else {
|
||||
GetLogo(w, r)
|
||||
return
|
||||
@ -57,6 +76,5 @@ func GetPreview(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
cacheTime := utils.GetCacheDurationSecondsForPath(imagePath)
|
||||
writeBytesAsImage(imageBytes, contentTypeGIF, w, cacheTime)
|
||||
writeBytesAsImage(imageBytes, contentTypeGIF, w, httpCacheTime)
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core"
|
||||
"github.com/owncast/owncast/core/cache"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/models"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
@ -18,6 +21,8 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var gc = cache.GetGlobalCache()
|
||||
|
||||
// IndexHandler handles the default index route.
|
||||
func IndexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.EnableCors(w)
|
||||
@ -121,6 +126,17 @@ type MetadataPage struct {
|
||||
// Return a basic HTML page with server-rendered metadata from the config
|
||||
// to give to Opengraph clients and web scrapers (bots, web crawlers, etc).
|
||||
func handleScraperMetadataPage(w http.ResponseWriter, r *http.Request) {
|
||||
cacheKey := "bot-scraper-html"
|
||||
cacheHtmlExpiration := time.Duration(10) * time.Second
|
||||
c := gc.GetOrCreateCache(cacheKey, cacheHtmlExpiration)
|
||||
|
||||
cachedHtml := c.GetValueForKey(cacheKey)
|
||||
if cachedHtml != nil {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
_, _ = w.Write(cachedHtml)
|
||||
return
|
||||
}
|
||||
|
||||
tmpl, err := static.GetBotMetadataTemplate()
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
@ -173,11 +189,18 @@ func handleScraperMetadataPage(w http.ResponseWriter, r *http.Request) {
|
||||
SocialHandles: data.GetSocialHandles(),
|
||||
}
|
||||
|
||||
// Cache the rendered HTML
|
||||
var b bytes.Buffer
|
||||
if err := tmpl.Execute(&b, metadata); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
c.Set(cacheKey, b.Bytes())
|
||||
|
||||
// Set a cache header
|
||||
middleware.SetCachingHeaders(w, r)
|
||||
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
if err := tmpl.Execute(w, metadata); err != nil {
|
||||
if _, err = w.Write(b.Bytes()); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
82
core/cache/cache.go
vendored
Normal file
82
core/cache/cache.go
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/jellydator/ttlcache/v3"
|
||||
)
|
||||
|
||||
// CacheContainer is a container for all caches.
|
||||
type CacheContainer struct {
|
||||
caches map[string]*CacheInstance
|
||||
}
|
||||
|
||||
// CacheInstance is a single cache instance.
|
||||
type CacheInstance struct {
|
||||
cache *ttlcache.Cache[string, []byte]
|
||||
}
|
||||
|
||||
// This is the global singleton instance. (To be removed after refactor).
|
||||
var _instance *CacheContainer
|
||||
|
||||
// NewCache creates a new cache instance.
|
||||
func NewGlobalCache() *CacheContainer {
|
||||
_instance = &CacheContainer{
|
||||
caches: make(map[string]*CacheInstance),
|
||||
}
|
||||
|
||||
return _instance
|
||||
}
|
||||
|
||||
// GetCache returns the cache instance.
|
||||
func GetGlobalCache() *CacheContainer {
|
||||
if _instance != nil {
|
||||
return _instance
|
||||
}
|
||||
return NewGlobalCache()
|
||||
}
|
||||
|
||||
// GetOrCreateCache returns the cache instance or creates a new one.
|
||||
func (c *CacheContainer) GetOrCreateCache(name string, expiration time.Duration) *CacheInstance {
|
||||
if _, ok := c.caches[name]; !ok {
|
||||
c.CreateCache(name, expiration)
|
||||
}
|
||||
return c.caches[name]
|
||||
}
|
||||
|
||||
// CreateCache creates a new cache instance.
|
||||
func (c *CacheContainer) CreateCache(name string, expiration time.Duration) *CacheInstance {
|
||||
cache := ttlcache.New[string, []byte](
|
||||
ttlcache.WithTTL[string, []byte](expiration),
|
||||
ttlcache.WithDisableTouchOnHit[string, []byte](),
|
||||
)
|
||||
ci := &CacheInstance{cache: cache}
|
||||
c.caches[name] = ci
|
||||
go cache.Start()
|
||||
return ci
|
||||
}
|
||||
|
||||
// GetCache returns the cache instance.
|
||||
func (c *CacheContainer) GetCache(name string) *CacheInstance {
|
||||
return c.caches[name]
|
||||
}
|
||||
|
||||
// GetValueForKey returns the value for the given key.
|
||||
func (ci *CacheInstance) GetValueForKey(key string) []byte {
|
||||
value := ci.cache.Get(key, ttlcache.WithDisableTouchOnHit[string, []byte]())
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if value.IsExpired() {
|
||||
return nil
|
||||
}
|
||||
|
||||
val := value.Value()
|
||||
return val
|
||||
}
|
||||
|
||||
// Set sets the value for the given key..
|
||||
func (ci *CacheInstance) Set(key string, value []byte) {
|
||||
ci.cache.Set(key, value, 0)
|
||||
}
|
72
core/cache/cache_test.go
vendored
Normal file
72
core/cache/cache_test.go
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
expiration := 5 * time.Second
|
||||
globalCache := GetGlobalCache()
|
||||
assert.NotNil(t, globalCache, "NewGlobalCache should return a non-nil instance")
|
||||
assert.Equal(t, globalCache, GetGlobalCache(), "GetGlobalCache should return the created instance")
|
||||
|
||||
cacheName := "testCache"
|
||||
globalCache.CreateCache(cacheName, expiration)
|
||||
|
||||
createdCache := globalCache.GetCache(cacheName)
|
||||
assert.NotNil(t, createdCache, "GetCache should return a non-nil cache")
|
||||
|
||||
key := "testKey"
|
||||
value := []byte("testValue")
|
||||
createdCache.Set(key, value)
|
||||
|
||||
// Wait for cache to expire
|
||||
time.Sleep(expiration + 1*time.Second)
|
||||
|
||||
// Verify that the cache has expired
|
||||
ci := globalCache.GetCache(cacheName)
|
||||
cachedValue := ci.GetValueForKey(key)
|
||||
assert.Nil(t, cachedValue, "Cache should not contain the value after expiration")
|
||||
}
|
||||
|
||||
func TestConcurrentAccess(t *testing.T) {
|
||||
// Test concurrent access to the cache
|
||||
globalCache := NewGlobalCache()
|
||||
cacheName := "concurrentCache"
|
||||
expiration := 5 * time.Second
|
||||
globalCache.CreateCache(cacheName, expiration)
|
||||
|
||||
// Start multiple goroutines to access the cache concurrently
|
||||
numGoroutines := 10
|
||||
keyPrefix := "key"
|
||||
valuePrefix := "value"
|
||||
|
||||
done := make(chan struct{})
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
go func(index int) {
|
||||
defer func() { done <- struct{}{} }()
|
||||
|
||||
cache := globalCache.GetCache(cacheName)
|
||||
key := keyPrefix + strconv.Itoa(index)
|
||||
value := valuePrefix + strconv.Itoa(index)
|
||||
|
||||
cache.Set(key, []byte(value))
|
||||
|
||||
// Simulate some work
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
ci := globalCache.GetCache(cacheName)
|
||||
cachedValue := string(ci.GetValueForKey(key))
|
||||
assert.Equal(t, value, cachedValue, "Cached value should match the set value")
|
||||
}(i)
|
||||
}
|
||||
|
||||
// Wait for all goroutines to finish
|
||||
for i := 0; i < numGoroutines; i++ {
|
||||
<-done
|
||||
}
|
||||
}
|
@ -13,19 +13,21 @@ 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/core/user"
|
||||
"github.com/owncast/owncast/geoip"
|
||||
)
|
||||
|
||||
// Client represents a single chat client.
|
||||
type Client struct {
|
||||
ConnectedAt time.Time `json:"connectedAt"`
|
||||
timeoutTimer *time.Timer
|
||||
rateLimiter *rate.Limiter
|
||||
conn *websocket.Conn
|
||||
User *user.User `json:"user"`
|
||||
server *Server
|
||||
Geo *geoip.GeoDetails `json:"geo"`
|
||||
ConnectedAt time.Time `json:"connectedAt"`
|
||||
timeoutTimer *time.Timer
|
||||
rateLimiter *rate.Limiter
|
||||
messageFilter *ChatMessageFilter
|
||||
conn *websocket.Conn
|
||||
User *user.User `json:"user"`
|
||||
server *Server
|
||||
Geo *geoip.GeoDetails `json:"geo"`
|
||||
// Buffered channel of outbound messages.
|
||||
send chan []byte
|
||||
accessToken string
|
||||
@ -90,6 +92,7 @@ func (c *Client) readPump() {
|
||||
// Allow 3 messages every two seconds.
|
||||
limit := rate.Every(2 * time.Second / 3)
|
||||
c.rateLimiter = rate.NewLimiter(limit, 1)
|
||||
c.messageFilter = NewMessageFilter()
|
||||
|
||||
defer func() {
|
||||
c.close()
|
||||
@ -129,6 +132,12 @@ func (c *Client) readPump() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this message passes the optional language filter
|
||||
if data.GetChatSlurFilterEnabled() && !c.messageFilter.Allow(string(message)) {
|
||||
c.sendAction("Sorry, that message contained language that is not allowed in this chat.")
|
||||
continue
|
||||
}
|
||||
|
||||
message = bytes.TrimSpace(bytes.ReplaceAll(message, newline, space))
|
||||
c.handleEvent(message)
|
||||
}
|
||||
@ -200,7 +209,13 @@ func (c *Client) close() {
|
||||
}
|
||||
|
||||
func (c *Client) passesRateLimit() bool {
|
||||
return c.rateLimiter.Allow() && !c.inTimeout
|
||||
// If spam rate limiting is disabled, or the user is a moderator, always
|
||||
// allow the message.
|
||||
if !data.GetChatSpamProtectionEnabled() || c.User.IsModerator() {
|
||||
return true
|
||||
}
|
||||
|
||||
return (c.rateLimiter.Allow() && !c.inTimeout)
|
||||
}
|
||||
|
||||
func (c *Client) startChatRejectionTimeout() {
|
||||
|
18
core/chat/messageFilter.go
Normal file
18
core/chat/messageFilter.go
Normal file
@ -0,0 +1,18 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
goaway "github.com/TwiN/go-away"
|
||||
)
|
||||
|
||||
// ChatMessageFilter is a allow/deny chat message filter.
|
||||
type ChatMessageFilter struct{}
|
||||
|
||||
// NewMessageFilter will return an instance of the chat message filter.
|
||||
func NewMessageFilter() *ChatMessageFilter {
|
||||
return &ChatMessageFilter{}
|
||||
}
|
||||
|
||||
// Allow will test if this message should be allowed to be sent.
|
||||
func (*ChatMessageFilter) Allow(message string) bool {
|
||||
return !goaway.IsProfane(message)
|
||||
}
|
39
core/chat/messageFilter_test.go
Normal file
39
core/chat/messageFilter_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package chat
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFiltering(t *testing.T) {
|
||||
filter := NewMessageFilter()
|
||||
|
||||
filteredTestMessages := []string{
|
||||
"Hello, fucking world!",
|
||||
"Suck my dick",
|
||||
"Eat my ass",
|
||||
"fuck this shit",
|
||||
"@$$h073",
|
||||
"F u C k th1$ $h!t",
|
||||
"u r fag",
|
||||
"fucking sucks",
|
||||
}
|
||||
|
||||
unfilteredTestMessages := []string{
|
||||
"bass fish",
|
||||
"assumptions",
|
||||
}
|
||||
|
||||
for _, m := range filteredTestMessages {
|
||||
result := filter.Allow(m)
|
||||
if result {
|
||||
t.Errorf("%s should be seen as a filtered profane message", m)
|
||||
}
|
||||
}
|
||||
|
||||
for _, m := range unfilteredTestMessages {
|
||||
result := filter.Allow(m)
|
||||
if !result {
|
||||
t.Errorf("%s should not be filtered", m)
|
||||
}
|
||||
}
|
||||
}
|
@ -96,6 +96,13 @@ func (s *Server) Addclient(conn *websocket.Conn, user *user.User, accessToken st
|
||||
|
||||
shouldSendJoinedMessages := data.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
|
||||
// GetClientsForUser already has a lock.
|
||||
if existingConnectedClients, _ := GetClientsForUser(user.ID); len(existingConnectedClients) > 0 {
|
||||
shouldSendJoinedMessages = false
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
{
|
||||
// If there is a pending disconnect timer then clear it.
|
||||
|
@ -104,7 +104,7 @@ func transitionToOfflineVideoStreamContent() {
|
||||
_transcoder.SetLatencyLevel(models.GetLatencyLevel(4))
|
||||
_transcoder.SetIsEvent(true)
|
||||
|
||||
offlineFilePath, err := saveOfflineClipToDisk("offline.ts")
|
||||
offlineFilePath, err := saveOfflineClipToDisk("offline-v2.ts")
|
||||
if err != nil {
|
||||
log.Fatalln("unable to save offline clip:", err)
|
||||
}
|
||||
|
@ -59,6 +59,8 @@ const (
|
||||
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"
|
||||
@ -528,6 +530,36 @@ func GetChatEstbalishedUsersOnlyMode() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// SetChatSpamProtectionEnabled will enable chat spam protection if set to true.
|
||||
func SetChatSpamProtectionEnabled(enabled bool) error {
|
||||
return _datastore.SetBool(chatSpamProtectionEnabledKey, enabled)
|
||||
}
|
||||
|
||||
// GetChatSpamProtectionEnabled will return if chat spam protection is enabled.
|
||||
func GetChatSpamProtectionEnabled() bool {
|
||||
enabled, err := _datastore.GetBool(chatSpamProtectionEnabledKey)
|
||||
if err == nil {
|
||||
return enabled
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// SetChatSlurFilterEnabled will enable the chat slur filter.
|
||||
func SetChatSlurFilterEnabled(enabled bool) error {
|
||||
return _datastore.SetBool(chatSlurFilterEnabledKey, enabled)
|
||||
}
|
||||
|
||||
// GetChatSlurFilterEnabled will return if the chat slur filter is enabled.
|
||||
func GetChatSlurFilterEnabled() bool {
|
||||
enabled, err := _datastore.GetBool(chatSlurFilterEnabledKey)
|
||||
if err == nil {
|
||||
return enabled
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// GetExternalActions will return the registered external actions.
|
||||
func GetExternalActions() []models.ExternalAction {
|
||||
configEntry, err := _datastore.Get(externalActionsKey)
|
||||
|
@ -36,7 +36,7 @@ func appendOfflineToVariantPlaylist(index int, playlistFilePath string) {
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-DISCONTINUITY\n")
|
||||
// If "offline" content gets changed then change the duration below
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXTINF:8.000000,\n")
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("offline.ts\n")
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("offline-v2.ts\n")
|
||||
_, _ = atomicWriteTmpPlaylistFile.WriteString("#EXT-X-ENDLIST\n")
|
||||
|
||||
if err := atomicWriteTmpPlaylistFile.Close(); err != nil {
|
||||
|
@ -5,10 +5,8 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
)
|
||||
|
||||
@ -62,36 +60,12 @@ func (s *LocalStorage) Save(filePath string, retryCount int) (string, error) {
|
||||
return filePath, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
buffer := 10
|
||||
baseDirectory := config.HLSStoragePath
|
||||
|
||||
files, err := getAllFilesRecursive(baseDirectory)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable find old video files for cleanup")
|
||||
}
|
||||
|
||||
// Delete old private HLS files on disk
|
||||
for directory := range files {
|
||||
files := files[directory]
|
||||
if len(files) < maxNumber+buffer {
|
||||
continue
|
||||
}
|
||||
|
||||
filesToDelete := files[maxNumber+buffer:]
|
||||
log.Traceln("Deleting", len(filesToDelete), "old files from", baseDirectory, "for video variant", directory)
|
||||
|
||||
for _, file := range filesToDelete {
|
||||
fileToDelete := filepath.Join(baseDirectory, directory, file.Name())
|
||||
err := os.Remove(fileToDelete)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete old video files")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return localCleanup(maxNumber + buffer)
|
||||
}
|
||||
|
||||
func getAllFilesRecursive(baseDirectory string) (map[string][]os.FileInfo, error) {
|
||||
|
39
core/storageproviders/localCleanup.go
Normal file
39
core/storageproviders/localCleanup.go
Normal file
@ -0,0 +1,39 @@
|
||||
package storageproviders
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/pkg/errors"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func localCleanup(maxNumber int) error {
|
||||
baseDirectory := config.HLSStoragePath
|
||||
|
||||
files, err := getAllFilesRecursive(baseDirectory)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable find old video files for cleanup")
|
||||
}
|
||||
|
||||
// Delete old private HLS files on disk
|
||||
for directory := range files {
|
||||
files := files[directory]
|
||||
if len(files) < maxNumber {
|
||||
continue
|
||||
}
|
||||
|
||||
filesToDelete := files[maxNumber:]
|
||||
log.Traceln("Deleting", len(filesToDelete), "old files from", baseDirectory, "for video variant", directory)
|
||||
|
||||
for _, file := range filesToDelete {
|
||||
fileToDelete := filepath.Join(baseDirectory, directory, file.Name())
|
||||
err := os.Remove(fileToDelete)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "unable to delete old video files")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/owncast/owncast/core/data"
|
||||
@ -26,26 +27,29 @@ import (
|
||||
|
||||
// S3Storage is the s3 implementation of a storage provider.
|
||||
type S3Storage struct {
|
||||
sess *session.Session
|
||||
// If we try to upload a playlist but it is not yet on disk
|
||||
// then keep a reference to it here.
|
||||
queuedPlaylistUpdates map[string]string
|
||||
|
||||
s3Client *s3.S3
|
||||
|
||||
uploader *s3manager.Uploader
|
||||
|
||||
// If we try to upload a playlist but it is not yet on disk
|
||||
// then keep a reference to it here.
|
||||
queuedPlaylistUpdates map[string]string
|
||||
sess *session.Session
|
||||
s3Secret string
|
||||
|
||||
s3Bucket string
|
||||
s3Region string
|
||||
s3ServingEndpoint string
|
||||
s3AccessKey string
|
||||
s3Secret string
|
||||
s3ACL string
|
||||
s3PathPrefix string
|
||||
|
||||
s3Endpoint string
|
||||
host string
|
||||
|
||||
lock sync.Mutex
|
||||
|
||||
s3ForcePathStyle bool
|
||||
}
|
||||
|
||||
@ -53,6 +57,7 @@ type S3Storage struct {
|
||||
func NewS3Storage() *S3Storage {
|
||||
return &S3Storage{
|
||||
queuedPlaylistUpdates: make(map[string]string),
|
||||
lock: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
@ -126,6 +131,8 @@ func (s *S3Storage) VariantPlaylistWritten(localFilePath string) {
|
||||
// We are uploading the variant playlist after uploading the segment
|
||||
// to make sure we're not referring to files in a playlist that don't
|
||||
// yet exist. See SegmentWritten.
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if _, ok := s.queuedPlaylistUpdates[localFilePath]; ok {
|
||||
if _, err := s.Save(localFilePath, 0); err != nil {
|
||||
log.Errorln(err)
|
||||
@ -195,19 +202,23 @@ func (s *S3Storage) Save(filePath string, retryCount int) (string, error) {
|
||||
return s.Save(filePath, retryCount+1)
|
||||
}
|
||||
|
||||
// Upload failure. Remove the local file.
|
||||
s.removeLocalFile(filePath)
|
||||
|
||||
return "", fmt.Errorf("Giving up uploading %s to object storage %s", filePath, s.s3Endpoint)
|
||||
}
|
||||
|
||||
// Upload success. Remove the local file.
|
||||
s.removeLocalFile(filePath)
|
||||
|
||||
return response.Location, nil
|
||||
}
|
||||
|
||||
// Cleanup will fire the different cleanup tasks required.
|
||||
func (s *S3Storage) Cleanup() error {
|
||||
if err := s.RemoteCleanup(); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
|
||||
return localCleanup(4)
|
||||
}
|
||||
|
||||
// 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
|
||||
buffer := 20
|
||||
@ -269,14 +280,6 @@ func (s *S3Storage) getDeletableVideoSegmentsWithOffset(offset int) ([]s3object,
|
||||
return objectsToDelete, nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) removeLocalFile(filePath string) {
|
||||
cleanFilepath := filepath.Clean(filePath)
|
||||
|
||||
if err := os.Remove(cleanFilepath); err != nil {
|
||||
log.Errorln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *S3Storage) deleteObjects(objects []s3object) {
|
||||
keys := make([]*s3.ObjectIdentifier, len(objects))
|
||||
for i, object := range objects {
|
||||
|
@ -93,7 +93,7 @@ func SetStreamAsDisconnected() {
|
||||
_stats.LastConnectTime = nil
|
||||
_broadcaster = nil
|
||||
|
||||
offlineFilename := "offline.ts"
|
||||
offlineFilename := "offline-v2.ts"
|
||||
|
||||
offlineFilePath, err := saveOfflineClipToDisk(offlineFilename)
|
||||
if err != nil {
|
||||
|
2347
docs/api/index.html
2347
docs/api/index.html
File diff suppressed because one or more lines are too long
51
go.mod
51
go.mod
@ -1,16 +1,16 @@
|
||||
module github.com/owncast/owncast
|
||||
|
||||
go 1.21
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/aws/aws-sdk-go v1.47.9
|
||||
github.com/aws/aws-sdk-go v1.53.5
|
||||
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/gorilla/websocket v1.5.1
|
||||
github.com/grafov/m3u8 v0.12.0
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible
|
||||
github.com/mattn/go-sqlite3 v1.14.17
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/microcosm-cc/bluemonday v1.0.26
|
||||
github.com/nareix/joy5 v0.0.0-20210317075623-2c912ca30590
|
||||
github.com/oschwald/geoip2-golang v1.9.0
|
||||
@ -18,9 +18,9 @@ require (
|
||||
github.com/schollz/sqlite3dump v1.3.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569
|
||||
github.com/yuin/goldmark v1.6.0
|
||||
golang.org/x/mod v0.14.0
|
||||
golang.org/x/time v0.4.0
|
||||
github.com/yuin/goldmark v1.7.1
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/time v0.5.0
|
||||
)
|
||||
|
||||
require (
|
||||
@ -30,53 +30,62 @@ require (
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.3 // indirect
|
||||
golang.org/x/crypto v0.15.0 // indirect
|
||||
golang.org/x/net v0.18.0
|
||||
golang.org/x/sys v0.14.0 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
golang.org/x/crypto v0.23.0 // indirect
|
||||
golang.org/x/net v0.25.0
|
||||
golang.org/x/sys v0.20.0 // indirect
|
||||
)
|
||||
|
||||
require github.com/prometheus/client_golang v1.17.0
|
||||
require github.com/prometheus/client_golang v1.19.1
|
||||
|
||||
require (
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 // indirect
|
||||
github.com/prometheus/common v0.44.0 // indirect
|
||||
github.com/prometheus/procfs v0.11.1 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
google.golang.org/protobuf v1.31.0 // indirect
|
||||
github.com/prometheus/client_model v0.5.0 // indirect
|
||||
github.com/prometheus/common v0.48.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
golang.org/x/text v0.15.0 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/nakabonne/tstorage v0.3.6
|
||||
github.com/shirou/gopsutil/v3 v3.23.10
|
||||
github.com/shirou/gopsutil/v3 v3.24.4
|
||||
)
|
||||
|
||||
require github.com/SherClockHolmes/webpush-go v1.3.0
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-test/deep v1.0.4 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/oschwald/maxminddb-golang v1.11.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
golang.org/x/sync v0.3.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/CAFxX/httpcompression v0.0.9
|
||||
github.com/TwiN/go-away v1.6.13
|
||||
github.com/andybalholm/cascadia v1.3.2
|
||||
github.com/go-chi/chi/v5 v5.0.12
|
||||
github.com/jellydator/ttlcache/v3 v3.2.0
|
||||
github.com/mssola/user_agent v0.6.0
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/yuin/goldmark-emoji v1.0.2
|
||||
gopkg.in/evanphx/json-patch.v5 v5.7.0
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0
|
||||
mvdan.cc/xurls v1.1.0
|
||||
)
|
||||
|
||||
|
166
go.sum
166
go.sum
@ -1,25 +1,37 @@
|
||||
github.com/CAFxX/httpcompression v0.0.9 h1:0ue2X8dOLEpxTm8tt+OdHcgA+gbDge0OqFQWGKSqgrg=
|
||||
github.com/CAFxX/httpcompression v0.0.9/go.mod h1:XX8oPZA+4IDcfZ0A71Hz0mZsv/YJOgYygkFhizVPilM=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/SherClockHolmes/webpush-go v1.3.0 h1:CAu3FvEE9QS4drc3iKNgpBWFfGqNthKlZhp5QpYnu6k=
|
||||
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/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=
|
||||
github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
|
||||
github.com/aws/aws-sdk-go v1.46.6 h1:6wFnNC9hETIZLMf6SOTN7IcclrOGwp/n9SLp8Pjt6E8=
|
||||
github.com/aws/aws-sdk-go v1.46.6/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
|
||||
github.com/aws/aws-sdk-go v1.47.9 h1:rarTsos0mA16q+huicGx0e560aYRtOucV5z2Mw23JRY=
|
||||
github.com/aws/aws-sdk-go v1.47.9/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/aws/aws-sdk-go v1.50.33 h1:/SKPJ7ZVPCFOYZyTKo5YdjeUEeOn2J2M0qfDTXWAoEU=
|
||||
github.com/aws/aws-sdk-go v1.50.33/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go v1.51.17 h1:Cfa40lCdjv9OxC3X1Ks3a6O1Tu3gOANSyKHOSw/zuWU=
|
||||
github.com/aws/aws-sdk-go v1.51.17/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go v1.51.23 h1:/3TEdsEE/aHmdKGw2NrOp7Sdea76zfffGkTTSXTsDxY=
|
||||
github.com/aws/aws-sdk-go v1.51.23/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
github.com/aws/aws-sdk-go v1.53.5 h1:1OcVWMjGlwt7EU5OWmmEEXqaYfmX581EK317QJZXItM=
|
||||
github.com/aws/aws-sdk-go v1.53.5/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
|
||||
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 v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/dave/jennifer v1.3.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
|
||||
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/go-chi/chi/v5 v5.0.12 h1:9euLV5sTrTNTRUU9POmDUvfxyj6LAABLUcEWO+JJb4s=
|
||||
github.com/go-chi/chi/v5 v5.0.12/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/go-fed/httpsig v0.1.1-0.20190914113940-c2de3672e5b5/go.mod h1:T56HUNYZUQ1AGUzhAYPugZfp36sKApVnGBgKlIY+aIE=
|
||||
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
|
||||
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
|
||||
@ -31,32 +43,36 @@ github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3a
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f h1:jopqB+UTSdJGEJT8tEqYyE29zN91fi2827oLET8tl7k=
|
||||
github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
||||
github.com/grafov/m3u8 v0.12.0 h1:T6iTwTsSEtMcwkayef+FJO8kj+Sglr4Lh81Zj8Ked/4=
|
||||
github.com/grafov/m3u8 v0.12.0/go.mod h1:nqzOkfBiZJENr52zTVd/Dcl03yzphIMbJqkXGu+u080=
|
||||
github.com/jellydator/ttlcache/v3 v3.2.0 h1:6lqVJ8X3ZaUwvzENqPAobDsXNExfUJd61u++uW8a3LE=
|
||||
github.com/jellydator/ttlcache/v3 v3.2.0/go.mod h1:hi7MGFdMAwZna5n2tuvh63DvFLzVKySzCVW6+0gA2n4=
|
||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
|
||||
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8=
|
||||
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
|
||||
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
|
||||
@ -66,10 +82,8 @@ 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.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
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/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58=
|
||||
github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs=
|
||||
github.com/mssola/user_agent v0.6.0 h1:uwPR4rtWlCHRFyyP9u2KOV0u8iQXmS7Z7feTrstQwk4=
|
||||
@ -80,6 +94,8 @@ github.com/nakabonne/tstorage v0.3.6 h1:usp7pTohax8mynnFiUSUQ2QVBCKLCkYx3gmb3+rJ
|
||||
github.com/nakabonne/tstorage v0.3.6/go.mod h1:1xUrK3s1MXSlU6dn96xHerHx/MdO4BGmsAHEUbsaOxU=
|
||||
github.com/nareix/joy5 v0.0.0-20210317075623-2c912ca30590 h1:PnxRU8L8Y2q82vFC2QdNw23Dm2u6WrjecIdpXjiYbXM=
|
||||
github.com/nareix/joy5 v0.0.0-20210317075623-2c912ca30590/go.mod h1:XmAOs6UJXpNXRwKk+KY/nv5kL6xXYXyellk+A1pTlko=
|
||||
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc=
|
||||
github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y=
|
||||
github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0=
|
||||
@ -95,22 +111,28 @@ 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.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16 h1:v7DLqVdK4VrYkVD5diGdl4sxJurKJEMnODWRJlxV9oM=
|
||||
github.com/prometheus/client_model v0.4.1-0.20230718164431-9a2bf3000d16/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI=
|
||||
github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY=
|
||||
github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU=
|
||||
github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k=
|
||||
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
|
||||
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
|
||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
||||
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
|
||||
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
|
||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
|
||||
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
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/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E=
|
||||
github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA=
|
||||
github.com/shirou/gopsutil/v3 v3.23.10 h1:/N42opWlYzegYaVkWejXWJpbzKv2JDy3mrgGzKsh9hM=
|
||||
github.com/shirou/gopsutil/v3 v3.23.10/go.mod h1:JIE26kpucQi+innVlAUnIEOSBhBUkirr5b44yr55+WE=
|
||||
github.com/shirou/gopsutil/v3 v3.24.2 h1:kcR0erMbLg5/3LcInpw0X/rrPSqq4CDPyI6A6ZRC18Y=
|
||||
github.com/shirou/gopsutil/v3 v3.24.2/go.mod h1:tSg/594BcA+8UdQU2XcW803GWYgdtauFFPgJCJKZlVk=
|
||||
github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
|
||||
github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
|
||||
github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
@ -119,16 +141,19 @@ 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=
|
||||
github.com/spf13/pflag v1.0.4-0.20181223182923-24fa6976df40/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
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/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=
|
||||
@ -140,44 +165,52 @@ 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.3.7/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.6.0 h1:boZcn2GTjpsynOsC0iJHnBWa4Bi0qzfJjthwauItG68=
|
||||
github.com/yuin/goldmark v1.6.0/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA=
|
||||
github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
|
||||
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
|
||||
github.com/yuin/goldmark-emoji v1.0.2 h1:c/RgTShNgHTtc6xdz2KKI74jJr6rWi7FPgnP9GAsO5s=
|
||||
github.com/yuin/goldmark-emoji v1.0.2/go.mod h1:RhP/RWpexdp+KHs7ghKnifRoIs/Bq4nDS7tRbCkOwKY=
|
||||
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
|
||||
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
|
||||
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
|
||||
golang.org/x/crypto v0.0.0-20180527072434-ab813273cd59/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
|
||||
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
||||
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
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.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
|
||||
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
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=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
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.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg=
|
||||
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
|
||||
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||
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=
|
||||
@ -188,51 +221,46 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.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.1.0/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.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
|
||||
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
||||
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
|
||||
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
|
||||
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.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.4.0 h1:Z81tqI5ddIoXDPvVQ7/7CC9TnLM7ubaFG2qXYd5BbYY=
|
||||
golang.org/x/time v0.4.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.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=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/evanphx/json-patch.v5 v5.7.0 h1:dGKGylPlZ/jus2g1YqhhyzfH0gPy2R8/MYUpW/OslTY=
|
||||
gopkg.in/evanphx/json-patch.v5 v5.7.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0 h1:hx1VU2SGj4F8r9b8GUwJLdc8DNO8sy79ZGui0G05GLo=
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
306
handler/admin.go
Normal file
306
handler/admin.go
Normal file
@ -0,0 +1,306 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers"
|
||||
"github.com/owncast/owncast/controllers/admin"
|
||||
"github.com/owncast/owncast/handler/generated"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
)
|
||||
|
||||
func (*ServerInterfaceImpl) StatusAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.Status)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) StatusAdminOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.Status)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DisconnectInboundConnection(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DisconnectInboundConnection)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DisconnectInboundConnectionOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DisconnectInboundConnection)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetServerConfig(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetServerConfig)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetServerConfigOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetServerConfig)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetViewersOverTime(w http.ResponseWriter, r *http.Request, params generated.GetViewersOverTimeParams) {
|
||||
middleware.RequireAdminAuth(admin.GetViewersOverTime)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetViewersOverTimeOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetViewersOverTime)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetActiveViewers(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetActiveViewers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetActiveViewersOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetActiveViewers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetHardwareStats(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetHardwareStats)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetHardwareStatsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetHardwareStats)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetConnectedChatClients(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetConnectedChatClients)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetConnectedChatClientsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetConnectedChatClients)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetChatMessagesAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetChatMessages)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetChatMessagesAdminOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetChatMessages)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateMessageVisibilityAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateMessageVisibility)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateMessageVisibilityAdminOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateMessageVisibility)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateUserEnabledAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateUserEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateUserEnabledAdminOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateUserEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetDisabledUsers(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetDisabledUsers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetDisabledUsersOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetDisabledUsers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) BanIPAddress(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.BanIPAddress)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) BanIPAddressOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.BanIPAddress)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UnbanIPAddress(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UnBanIPAddress)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UnbanIPAddressOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UnBanIPAddress)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetIPAddressBans(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetIPAddressBans)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetIPAddressBansOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetIPAddressBans)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateUserModerator(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateUserModerator)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateUserModeratorOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UpdateUserModerator)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetModerators(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetModerators)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetModeratorsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetModerators)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetLogs(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetLogs)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetLogsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetLogs)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetWarnings(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetWarnings)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetWarningsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetWarnings)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetFollowersAdmin(w http.ResponseWriter, r *http.Request, params generated.GetFollowersAdminParams) {
|
||||
middleware.RequireAdminAuth(middleware.HandlePagination(controllers.GetFollowers))(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetFollowersAdminOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(middleware.HandlePagination(controllers.GetFollowers))(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetPendingFollowRequests(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetPendingFollowRequests)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetPendingFollowRequestsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetPendingFollowRequests)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetBlockedAndRejectedFollowers(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetBlockedAndRejectedFollowers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetBlockedAndRejectedFollowersOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetBlockedAndRejectedFollowers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ApproveFollower(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.ApproveFollower)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ApproveFollowerOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.ApproveFollower)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UploadCustomEmoji(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UploadCustomEmoji)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UploadCustomEmojiOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.UploadCustomEmoji)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteCustomEmoji(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteCustomEmoji)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteCustomEmojiOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteCustomEmoji)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetWebhooks(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetWebhooks)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetWebhooksOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetWebhooks)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteWebhook)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteWebhookOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteWebhook)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) CreateWebhook(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.CreateWebhook)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) CreateWebhookOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.CreateWebhook)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetExternalAPIUsers(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetExternalAPIUsers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetExternalAPIUsersOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetExternalAPIUsers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteExternalAPIUser(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteExternalAPIUser)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeleteExternalAPIUserOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.DeleteExternalAPIUser)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) CreateExternalAPIUser(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.CreateExternalAPIUser)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) CreateExternalAPIUserOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.CreateExternalAPIUser)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateOptions)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateOptionsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateOptions)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateStart(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateStart)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateStartOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateStart)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateForceQuit(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateForceQuit)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) AutoUpdateForceQuitOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.AutoUpdateForceQuit)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ResetYPRegistration(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.ResetYPRegistration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ResetYPRegistrationOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.ResetYPRegistration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetVideoPlaybackMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetVideoPlaybackMetrics)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetVideoPlaybackMetricsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.GetVideoPlaybackMetrics)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendFederatedMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SendFederatedMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendFederatedMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SendFederatedMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetFederatedActions(w http.ResponseWriter, r *http.Request, params generated.GetFederatedActionsParams) {
|
||||
middleware.RequireAdminAuth(middleware.HandlePagination(admin.GetFederatedActions))(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetFederatedActionsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(middleware.HandlePagination(admin.GetFederatedActions))(w, r)
|
||||
}
|
34
handler/auth.go
Normal file
34
handler/auth.go
Normal file
@ -0,0 +1,34 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers/auth/fediverse"
|
||||
"github.com/owncast/owncast/controllers/auth/indieauth"
|
||||
"github.com/owncast/owncast/handler/generated"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
)
|
||||
|
||||
func (*ServerInterfaceImpl) StartIndieAuthFlow(w http.ResponseWriter, r *http.Request, params generated.StartIndieAuthFlowParams) {
|
||||
middleware.RequireUserAccessToken(indieauth.StartAuthFlow)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) HandleIndieAuthRedirect(w http.ResponseWriter, r *http.Request, params generated.HandleIndieAuthRedirectParams) {
|
||||
indieauth.HandleRedirect(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) HandleIndieAuthEndpointGet(w http.ResponseWriter, r *http.Request, params generated.HandleIndieAuthEndpointGetParams) {
|
||||
middleware.RequireAdminAuth(indieauth.HandleAuthEndpointGet)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) HandleIndieAuthEndpointPost(w http.ResponseWriter, r *http.Request) {
|
||||
indieauth.HandleAuthEndpointPost(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) RegisterFediverseOTPRequest(w http.ResponseWriter, r *http.Request, params generated.RegisterFediverseOTPRequestParams) {
|
||||
middleware.RequireUserAccessToken(fediverse.RegisterFediverseOTPRequest)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) VerifyFediverseOTPRequest(w http.ResponseWriter, r *http.Request) {
|
||||
fediverse.VerifyFediverseOTPRequest(w, r)
|
||||
}
|
368
handler/config.go
Normal file
368
handler/config.go
Normal file
@ -0,0 +1,368 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers/admin"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
)
|
||||
|
||||
func (*ServerInterfaceImpl) SetAdminPassword(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetAdminPassword)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetAdminPasswordOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetAdminPassword)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamKeys(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamKeys)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamKeysOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamKeys)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetExtraPageContent(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetExtraPageContent)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetExtraPageContentOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetExtraPageContent)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamTitle(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamTitle)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamTitleOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamTitle)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerName(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerName)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerNameOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerName)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerSummary(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerSummary)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerSummaryOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerSummary)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomOfflineMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomOfflineMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomOfflineMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomOfflineMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerWelcomeMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerWelcomeMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerWelcomeMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerWelcomeMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatDisabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatDisabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatDisabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatDisabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatJoinMessagesEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatJoinMessagesEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatJoinMessagesEnabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatJoinMessagesEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetEnableEstablishedChatUserMode(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetEnableEstablishedChatUserMode)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetEnableEstablishedChatUserModeOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetEnableEstablishedChatUserMode)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetForbiddenUsernameList(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetForbiddenUsernameList)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetForbiddenUsernameListOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetForbiddenUsernameList)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSuggestedUsernameList(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSuggestedUsernameList)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSuggestedUsernameListOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSuggestedUsernameList)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatSpamProtectionEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatSpamProtectionEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatSpamProtectionEnabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatSpamProtectionEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatSlurFilterEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatSlurFilterEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetChatSlurFilterEnabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetChatSlurFilterEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetVideoCodec(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetVideoCodec)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetVideoCodecOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetVideoCodec)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamLatencyLevel(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamLatencyLevel)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamLatencyLevelOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamLatencyLevel)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamOutputVariants(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamOutputVariants)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetStreamOutputVariantsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetStreamOutputVariants)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomColorVariableValues(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomColorVariableValues)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomColorVariableValuesOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomColorVariableValues)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetLogo(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetLogo)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetLogoOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetLogo)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetTags(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetTags)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetTagsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetTags)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFfmpegPath(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFfmpegPath)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFfmpegPathOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFfmpegPath)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetWebServerPort(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetWebServerPort)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetWebServerPortOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetWebServerPort)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetWebServerIP(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetWebServerIP)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetWebServerIPOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetWebServerIP)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetRTMPServerPort(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetRTMPServerPort)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetRTMPServerPortOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetRTMPServerPort)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSocketHostOverride(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSocketHostOverride)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSocketHostOverrideOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSocketHostOverride)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetVideoServingEndpoint(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetVideoServingEndpoint)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetVideoServingEndpointOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetVideoServingEndpoint)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetNSFW(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetNSFW)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetNSFWOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetNSFW)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDirectoryEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDirectoryEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDirectoryEnabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDirectoryEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSocialHandles(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSocialHandles)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetSocialHandlesOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetSocialHandles)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetS3Configuration(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetS3Configuration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetS3ConfigurationOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetS3Configuration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerURL(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerURL)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetServerURLOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetServerURL)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetExternalActions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetExternalActions)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetExternalActionsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetExternalActions)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomStyles(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomStyles)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomStylesOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomStyles)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomJavascript(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomJavascript)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetCustomJavascriptOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetCustomJavascript)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetHideViewerCount(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetHideViewerCount)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetHideViewerCountOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetHideViewerCount)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDisableSearchIndexing(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDisableSearchIndexing)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDisableSearchIndexingOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDisableSearchIndexing)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationEnabled(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationEnabledOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationActivityPrivate(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationActivityPrivate)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationActivityPrivateOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationActivityPrivate)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationShowEngagement(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationShowEngagement)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationShowEngagementOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationShowEngagement)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationUsername(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationUsername)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationUsernameOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationUsername)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationGoLiveMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationGoLiveMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationGoLiveMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationGoLiveMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationBlockDomains(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationBlockDomains)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetFederationBlockDomainsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetFederationBlockDomains)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDiscordNotificationConfiguration(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDiscordNotificationConfiguration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetDiscordNotificationConfigurationOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetDiscordNotificationConfiguration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetBrowserNotificationConfiguration(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetBrowserNotificationConfiguration)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SetBrowserNotificationConfigurationOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireAdminAuth(admin.SetBrowserNotificationConfiguration)(w, r)
|
||||
}
|
1342
handler/generated/generated-types.gen.go
Normal file
1342
handler/generated/generated-types.gen.go
Normal file
File diff suppressed because it is too large
Load Diff
6297
handler/generated/generated.gen.go
Normal file
6297
handler/generated/generated.gen.go
Normal file
File diff suppressed because it is too large
Load Diff
88
handler/handler.go
Normal file
88
handler/handler.go
Normal file
@ -0,0 +1,88 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers"
|
||||
"github.com/owncast/owncast/controllers/admin"
|
||||
"github.com/owncast/owncast/handler/generated"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
"github.com/owncast/owncast/yp"
|
||||
)
|
||||
|
||||
type ServerInterfaceImpl struct{}
|
||||
|
||||
// ensure ServerInterfaceImpl implements ServerInterface.
|
||||
var _ generated.ServerInterface = &ServerInterfaceImpl{}
|
||||
|
||||
func New() *ServerInterfaceImpl {
|
||||
return &ServerInterfaceImpl{}
|
||||
}
|
||||
|
||||
func (s *ServerInterfaceImpl) Handler() http.Handler {
|
||||
return generated.Handler(s)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetStatus(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.GetStatus(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetCustomEmojiList(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.GetCustomEmojiList(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetChatMessages(w http.ResponseWriter, r *http.Request, params generated.GetChatMessagesParams) {
|
||||
middleware.RequireUserAccessToken(controllers.GetChatMessages)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) RegisterAnonymousChatUser(w http.ResponseWriter, r *http.Request, params generated.RegisterAnonymousChatUserParams) {
|
||||
controllers.RegisterAnonymousChatUser(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) RegisterAnonymousChatUserOptions(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.RegisterAnonymousChatUser(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateMessageVisibility(w http.ResponseWriter, r *http.Request, params generated.UpdateMessageVisibilityParams) {
|
||||
middleware.RequireUserModerationScopeAccesstoken(admin.UpdateMessageVisibility)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) UpdateUserEnabled(w http.ResponseWriter, r *http.Request, params generated.UpdateUserEnabledParams) {
|
||||
middleware.RequireUserModerationScopeAccesstoken(admin.UpdateUserEnabled)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetWebConfig(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.GetWebConfig(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetYPResponse(w http.ResponseWriter, r *http.Request) {
|
||||
yp.GetYPResponse(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetAllSocialPlatforms(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.GetAllSocialPlatforms(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetVideoStreamOutputVariants(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.GetVideoStreamOutputVariants(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) Ping(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.Ping(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) RemoteFollow(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.RemoteFollow(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetFollowers(w http.ResponseWriter, r *http.Request, params generated.GetFollowersParams) {
|
||||
middleware.HandlePagination(controllers.GetFollowers)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ReportPlaybackMetrics(w http.ResponseWriter, r *http.Request) {
|
||||
controllers.ReportPlaybackMetrics(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) RegisterForLiveNotifications(w http.ResponseWriter, r *http.Request, params generated.RegisterForLiveNotificationsParams) {
|
||||
middleware.RequireUserAccessToken(controllers.RegisterForLiveNotifications)(w, r)
|
||||
}
|
120
handler/integrations.go
Normal file
120
handler/integrations.go
Normal file
@ -0,0 +1,120 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers"
|
||||
"github.com/owncast/owncast/controllers/admin"
|
||||
"github.com/owncast/owncast/core/user"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
|
||||
func (*ServerInterfaceImpl) SendSystemMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendSystemMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendSystemMessageToConnectedClient(w http.ResponseWriter, r *http.Request, clientId int) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessageToConnectedClient)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendSystemMessageToConnectedClientOptions(w http.ResponseWriter, r *http.Request, clientId int) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessageToConnectedClient)(w, r)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (*ServerInterfaceImpl) SendUserMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendUserMessage)(w, r)
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (*ServerInterfaceImpl) SendUserMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendUserMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendIntegrationChatMessage(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendIntegrationChatMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendIntegrationChatMessageOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendIntegrationChatMessage)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendChatAction(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendChatAction)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) SendChatActionOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendChatAction)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalUpdateMessageVisibility(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalUpdateMessageVisibility)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalUpdateMessageVisibilityOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalUpdateMessageVisibility)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalSetStreamTitle(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalSetStreamTitle)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalSetStreamTitleOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalSetStreamTitle)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalGetChatMessages(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, controllers.ExternalGetChatMessages)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalGetChatMessagesOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, controllers.ExternalGetChatMessages)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalGetConnectedChatClients(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalGetConnectedChatClients)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) ExternalGetConnectedChatClientsOptions(w http.ResponseWriter, r *http.Request) {
|
||||
middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalGetConnectedChatClients)(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) GetPrometheusAPI(w http.ResponseWriter, r *http.Request) {
|
||||
// might need to bring this out of the codegen
|
||||
middleware.RequireAdminAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler()
|
||||
})(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) PostPrometheusAPI(w http.ResponseWriter, r *http.Request) {
|
||||
// might need to bring this out of the codegen
|
||||
middleware.RequireAdminAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler()
|
||||
})(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) PutPrometheusAPI(w http.ResponseWriter, r *http.Request) {
|
||||
// might need to bring this out of the codegen
|
||||
middleware.RequireAdminAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler()
|
||||
})(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) DeletePrometheusAPI(w http.ResponseWriter, r *http.Request) {
|
||||
// might need to bring this out of the codegen
|
||||
middleware.RequireAdminAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler()
|
||||
})(w, r)
|
||||
}
|
||||
|
||||
func (*ServerInterfaceImpl) OptionsPrometheusAPI(w http.ResponseWriter, r *http.Request) {
|
||||
// might need to bring this out of the codegen
|
||||
middleware.RequireAdminAuth(func(w http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler()
|
||||
})(w, r)
|
||||
}
|
13
handler/moderation.go
Normal file
13
handler/moderation.go
Normal file
@ -0,0 +1,13 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/owncast/owncast/controllers/moderation"
|
||||
"github.com/owncast/owncast/handler/generated"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
)
|
||||
|
||||
func (*ServerInterfaceImpl) GetUserDetails(w http.ResponseWriter, r *http.Request, userId string, params generated.GetUserDetailsParams) {
|
||||
middleware.RequireUserModerationScopeAccesstoken(moderation.GetUserDetails)(w, r)
|
||||
}
|
2
main.go
2
main.go
@ -105,7 +105,7 @@ func main() {
|
||||
|
||||
go metrics.Start(core.GetStatus)
|
||||
|
||||
if err := router.Start(); err != nil {
|
||||
if err := router.Start(*enableVerboseLogging); err != nil {
|
||||
log.Fatalln("failed to start/run the router", err)
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ const (
|
||||
MessageSent EventType = "CHAT"
|
||||
// UserJoined is the event sent when a chat user join action takes place.
|
||||
UserJoined EventType = "USER_JOINED"
|
||||
// UserParted is the event sent when a chat user parted action takes place.
|
||||
UserParted EventType = "USER_PARTED"
|
||||
// UserNameChanged is the event sent when a chat username change takes place.
|
||||
UserNameChanged EventType = "NAME_CHANGE"
|
||||
// VisibiltyToggled is the event sent when a chat message's visibility changes.
|
||||
|
@ -19,6 +19,7 @@ type Webhook struct {
|
||||
var validEvents = []EventType{
|
||||
MessageSent,
|
||||
UserJoined,
|
||||
UserParted,
|
||||
UserNameChanged,
|
||||
VisibiltyToggled,
|
||||
StreamStarted,
|
||||
|
@ -2,7 +2,7 @@ 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. <br/><br/>Take note that only APIs listed specifically for external use, 3rd parties or for integration purposes are encouraged for external use. Internal APIs may change at any time and are used by the server and frontend itself.
|
||||
version: '0.1.0'
|
||||
version: '0.1.3'
|
||||
contact:
|
||||
name: Gabe Kangas
|
||||
email: gabek@real-ity.com
|
||||
|
@ -25,11 +25,9 @@ func RequireAdminAuth(handler http.HandlerFunc) http.HandlerFunc {
|
||||
password := data.GetAdminPassword()
|
||||
realm := "Owncast Authenticated Request"
|
||||
|
||||
// The following line is kind of a work around.
|
||||
// If you want HTTP Basic Auth + Cors it requires _explicit_ origins to be provided in the
|
||||
// Access-Control-Allow-Origin header. So we just pull out the origin header and specify it.
|
||||
// If we want to lock down admin APIs to not be CORS accessible for anywhere, this is where we would do that.
|
||||
w.Header().Set("Access-Control-Allow-Origin", r.Header.Get("Origin"))
|
||||
// Alow CORS only for localhost:3000 to support Owncast development.
|
||||
validAdminHost := "http://localhost:3000"
|
||||
w.Header().Set("Access-Control-Allow-Origin", validAdminHost)
|
||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
|
||||
|
||||
|
452
router/router.go
452
router/router.go
@ -3,415 +3,72 @@ package router
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/CAFxX/httpcompression"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/go-chi/chi/v5"
|
||||
chiMW "github.com/go-chi/chi/v5/middleware"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
|
||||
"github.com/owncast/owncast/activitypub"
|
||||
apControllers "github.com/owncast/owncast/activitypub/controllers"
|
||||
"github.com/owncast/owncast/config"
|
||||
"github.com/owncast/owncast/controllers"
|
||||
"github.com/owncast/owncast/controllers/admin"
|
||||
fediverseauth "github.com/owncast/owncast/controllers/auth/fediverse"
|
||||
"github.com/owncast/owncast/controllers/auth/indieauth"
|
||||
"github.com/owncast/owncast/controllers/moderation"
|
||||
"github.com/owncast/owncast/core/chat"
|
||||
"github.com/owncast/owncast/core/data"
|
||||
"github.com/owncast/owncast/core/user"
|
||||
"github.com/owncast/owncast/handler"
|
||||
"github.com/owncast/owncast/router/middleware"
|
||||
"github.com/owncast/owncast/utils"
|
||||
"github.com/owncast/owncast/yp"
|
||||
)
|
||||
|
||||
// Start starts the router for the http, ws, and rtmp.
|
||||
func Start() error {
|
||||
// The primary web app.
|
||||
http.HandleFunc("/", controllers.IndexHandler)
|
||||
func Start(enableVerboseLogging bool) error {
|
||||
// @behlers New Router
|
||||
r := chi.NewRouter()
|
||||
|
||||
// The admin web app.
|
||||
http.HandleFunc("/admin/", middleware.RequireAdminAuth(controllers.IndexHandler))
|
||||
// Middlewares
|
||||
if enableVerboseLogging {
|
||||
r.Use(chiMW.RequestLogger(&chiMW.DefaultLogFormatter{Logger: log.StandardLogger(), NoColor: true}))
|
||||
}
|
||||
r.Use(chiMW.Recoverer)
|
||||
|
||||
// Images
|
||||
http.HandleFunc("/thumbnail.jpg", controllers.GetThumbnail)
|
||||
http.HandleFunc("/preview.gif", controllers.GetPreview)
|
||||
http.HandleFunc("/logo", controllers.GetLogo)
|
||||
addStaticFileEndpoints(r)
|
||||
|
||||
// Custom Javascript
|
||||
http.HandleFunc("/customjavascript", controllers.ServeCustomJavascript)
|
||||
// websocket
|
||||
r.HandleFunc("/ws", chat.HandleClientConnection)
|
||||
|
||||
// Return a single emoji image.
|
||||
http.HandleFunc(config.EmojiDir, controllers.GetCustomEmojiImage)
|
||||
|
||||
// return the logo
|
||||
|
||||
// return a logo that's compatible with external social networks
|
||||
http.HandleFunc("/logo/external", controllers.GetCompatibleLogo)
|
||||
|
||||
// robots.txt
|
||||
http.HandleFunc("/robots.txt", controllers.GetRobotsDotTxt)
|
||||
|
||||
// status of the system
|
||||
http.HandleFunc("/api/status", controllers.GetStatus)
|
||||
|
||||
// custom emoji supported in the chat
|
||||
http.HandleFunc("/api/emoji", controllers.GetCustomEmojiList)
|
||||
|
||||
// chat rest api
|
||||
http.HandleFunc("/api/chat", middleware.RequireUserAccessToken(controllers.GetChatMessages))
|
||||
|
||||
// web config api
|
||||
http.HandleFunc("/api/config", controllers.GetWebConfig)
|
||||
|
||||
// return the YP protocol data
|
||||
http.HandleFunc("/api/yp", yp.GetYPResponse)
|
||||
|
||||
// list of all social platforms
|
||||
http.HandleFunc("/api/socialplatforms", controllers.GetAllSocialPlatforms)
|
||||
|
||||
// return the list of video variants available
|
||||
http.HandleFunc("/api/video/variants", controllers.GetVideoStreamOutputVariants)
|
||||
|
||||
// tell the backend you're an active viewer
|
||||
http.HandleFunc("/api/ping", controllers.Ping)
|
||||
|
||||
// register a new chat user
|
||||
http.HandleFunc("/api/chat/register", controllers.RegisterAnonymousChatUser)
|
||||
|
||||
// return remote follow details
|
||||
http.HandleFunc("/api/remotefollow", controllers.RemoteFollow)
|
||||
|
||||
// return followers
|
||||
http.HandleFunc("/api/followers", middleware.HandlePagination(controllers.GetFollowers))
|
||||
|
||||
// save client video playback metrics
|
||||
http.HandleFunc("/api/metrics/playback", controllers.ReportPlaybackMetrics)
|
||||
|
||||
// Register for notifications
|
||||
http.HandleFunc("/api/notifications/register", middleware.RequireUserAccessToken(controllers.RegisterForLiveNotifications))
|
||||
|
||||
// Authenticated admin requests
|
||||
|
||||
// Current inbound broadcaster
|
||||
http.HandleFunc("/api/admin/status", middleware.RequireAdminAuth(admin.Status))
|
||||
// serve files
|
||||
fs := http.FileServer(http.Dir(config.PublicFilesPath))
|
||||
r.Handle("/public/*", http.StripPrefix("/public/", fs))
|
||||
|
||||
// Return HLS video
|
||||
http.HandleFunc("/hls/", controllers.HandleHLSRequest)
|
||||
r.HandleFunc("/hls/*", controllers.HandleHLSRequest)
|
||||
|
||||
// Disconnect inbound stream
|
||||
http.HandleFunc("/api/admin/disconnect", middleware.RequireAdminAuth(admin.DisconnectInboundConnection))
|
||||
// The admin web app.
|
||||
r.HandleFunc("/admin/*", middleware.RequireAdminAuth(controllers.IndexHandler))
|
||||
|
||||
// Server config
|
||||
http.HandleFunc("/api/admin/serverconfig", middleware.RequireAdminAuth(admin.GetServerConfig))
|
||||
// Single ActivityPub Actor
|
||||
r.HandleFunc("/federation/user/*", middleware.RequireActivityPubOrRedirect(apControllers.ActorHandler))
|
||||
|
||||
// Get viewer count over time
|
||||
http.HandleFunc("/api/admin/viewersOverTime", middleware.RequireAdminAuth(admin.GetViewersOverTime))
|
||||
// Single AP object
|
||||
r.HandleFunc("/federation/*", middleware.RequireActivityPubOrRedirect(apControllers.ObjectHandler))
|
||||
|
||||
// Get active viewers
|
||||
http.HandleFunc("/api/admin/viewers", middleware.RequireAdminAuth(admin.GetActiveViewers))
|
||||
// The primary web app.
|
||||
r.HandleFunc("/*", controllers.IndexHandler)
|
||||
|
||||
// Get hardware stats
|
||||
http.HandleFunc("/api/admin/hardwarestats", middleware.RequireAdminAuth(admin.GetHardwareStats))
|
||||
|
||||
// Get a a detailed list of currently connected chat clients
|
||||
http.HandleFunc("/api/admin/chat/clients", middleware.RequireAdminAuth(admin.GetConnectedChatClients))
|
||||
|
||||
// Get all logs
|
||||
http.HandleFunc("/api/admin/logs", middleware.RequireAdminAuth(admin.GetLogs))
|
||||
|
||||
// Get warning/error logs
|
||||
http.HandleFunc("/api/admin/logs/warnings", middleware.RequireAdminAuth(admin.GetWarnings))
|
||||
|
||||
// Get all chat messages for the admin, unfiltered.
|
||||
http.HandleFunc("/api/admin/chat/messages", middleware.RequireAdminAuth(admin.GetChatMessages))
|
||||
|
||||
// Update chat message visibility
|
||||
http.HandleFunc("/api/admin/chat/messagevisibility", middleware.RequireAdminAuth(admin.UpdateMessageVisibility))
|
||||
|
||||
// Enable/disable a user
|
||||
http.HandleFunc("/api/admin/chat/users/setenabled", middleware.RequireAdminAuth(admin.UpdateUserEnabled))
|
||||
|
||||
// Ban/unban an IP address
|
||||
http.HandleFunc("/api/admin/chat/users/ipbans/create", middleware.RequireAdminAuth(admin.BanIPAddress))
|
||||
|
||||
// Remove an IP address ban
|
||||
http.HandleFunc("/api/admin/chat/users/ipbans/remove", middleware.RequireAdminAuth(admin.UnBanIPAddress))
|
||||
|
||||
// Return all the banned IP addresses
|
||||
http.HandleFunc("/api/admin/chat/users/ipbans", middleware.RequireAdminAuth(admin.GetIPAddressBans))
|
||||
|
||||
// Get a list of disabled users
|
||||
http.HandleFunc("/api/admin/chat/users/disabled", middleware.RequireAdminAuth(admin.GetDisabledUsers))
|
||||
|
||||
// Set moderator status for a user
|
||||
http.HandleFunc("/api/admin/chat/users/setmoderator", middleware.RequireAdminAuth(admin.UpdateUserModerator))
|
||||
|
||||
// Get a list of moderator users
|
||||
http.HandleFunc("/api/admin/chat/users/moderators", middleware.RequireAdminAuth(admin.GetModerators))
|
||||
|
||||
// return followers
|
||||
http.HandleFunc("/api/admin/followers", middleware.RequireAdminAuth(middleware.HandlePagination(controllers.GetFollowers)))
|
||||
|
||||
// Get a list of pending follow requests
|
||||
http.HandleFunc("/api/admin/followers/pending", middleware.RequireAdminAuth(admin.GetPendingFollowRequests))
|
||||
|
||||
// Get a list of rejected or blocked follows
|
||||
http.HandleFunc("/api/admin/followers/blocked", middleware.RequireAdminAuth(admin.GetBlockedAndRejectedFollowers))
|
||||
|
||||
// Set the following state of a follower or follow request.
|
||||
http.HandleFunc("/api/admin/followers/approve", middleware.RequireAdminAuth(admin.ApproveFollower))
|
||||
|
||||
// Upload custom emoji
|
||||
http.HandleFunc("/api/admin/emoji/upload", middleware.RequireAdminAuth(admin.UploadCustomEmoji))
|
||||
|
||||
// Delete custom emoji
|
||||
http.HandleFunc("/api/admin/emoji/delete", middleware.RequireAdminAuth(admin.DeleteCustomEmoji))
|
||||
|
||||
// Update config values
|
||||
|
||||
// Change the current streaming key in memory
|
||||
http.HandleFunc("/api/admin/config/adminpass", middleware.RequireAdminAuth(admin.SetAdminPassword))
|
||||
|
||||
// Set an array of valid stream keys
|
||||
http.HandleFunc("/api/admin/config/streamkeys", middleware.RequireAdminAuth(admin.SetStreamKeys))
|
||||
|
||||
// Change the extra page content in memory
|
||||
http.HandleFunc("/api/admin/config/pagecontent", middleware.RequireAdminAuth(admin.SetExtraPageContent))
|
||||
|
||||
// Stream title
|
||||
http.HandleFunc("/api/admin/config/streamtitle", middleware.RequireAdminAuth(admin.SetStreamTitle))
|
||||
|
||||
// Server name
|
||||
http.HandleFunc("/api/admin/config/name", middleware.RequireAdminAuth(admin.SetServerName))
|
||||
|
||||
// Server summary
|
||||
http.HandleFunc("/api/admin/config/serversummary", middleware.RequireAdminAuth(admin.SetServerSummary))
|
||||
|
||||
// Offline message
|
||||
http.HandleFunc("/api/admin/config/offlinemessage", middleware.RequireAdminAuth(admin.SetCustomOfflineMessage))
|
||||
|
||||
// Server welcome message
|
||||
http.HandleFunc("/api/admin/config/welcomemessage", middleware.RequireAdminAuth(admin.SetServerWelcomeMessage))
|
||||
|
||||
// Disable chat
|
||||
http.HandleFunc("/api/admin/config/chat/disable", middleware.RequireAdminAuth(admin.SetChatDisabled))
|
||||
|
||||
// Disable chat user join messages
|
||||
http.HandleFunc("/api/admin/config/chat/joinmessagesenabled", middleware.RequireAdminAuth(admin.SetChatJoinMessagesEnabled))
|
||||
|
||||
// Enable/disable chat established user mode
|
||||
http.HandleFunc("/api/admin/config/chat/establishedusermode", middleware.RequireAdminAuth(admin.SetEnableEstablishedChatUserMode))
|
||||
|
||||
// Set chat usernames that are not allowed
|
||||
http.HandleFunc("/api/admin/config/chat/forbiddenusernames", middleware.RequireAdminAuth(admin.SetForbiddenUsernameList))
|
||||
|
||||
// Set the suggested chat usernames that will be assigned automatically
|
||||
http.HandleFunc("/api/admin/config/chat/suggestedusernames", middleware.RequireAdminAuth(admin.SetSuggestedUsernameList))
|
||||
|
||||
// Set video codec
|
||||
http.HandleFunc("/api/admin/config/video/codec", middleware.RequireAdminAuth(admin.SetVideoCodec))
|
||||
|
||||
// Set style/color/css values
|
||||
http.HandleFunc("/api/admin/config/appearance", middleware.RequireAdminAuth(admin.SetCustomColorVariableValues))
|
||||
|
||||
// Return all webhooks
|
||||
http.HandleFunc("/api/admin/webhooks", middleware.RequireAdminAuth(admin.GetWebhooks))
|
||||
|
||||
// Delete a single webhook
|
||||
http.HandleFunc("/api/admin/webhooks/delete", middleware.RequireAdminAuth(admin.DeleteWebhook))
|
||||
|
||||
// Create a single webhook
|
||||
http.HandleFunc("/api/admin/webhooks/create", middleware.RequireAdminAuth(admin.CreateWebhook))
|
||||
|
||||
// Get all access tokens
|
||||
http.HandleFunc("/api/admin/accesstokens", middleware.RequireAdminAuth(admin.GetExternalAPIUsers))
|
||||
|
||||
// Delete a single access token
|
||||
http.HandleFunc("/api/admin/accesstokens/delete", middleware.RequireAdminAuth(admin.DeleteExternalAPIUser))
|
||||
|
||||
// Create a single access token
|
||||
http.HandleFunc("/api/admin/accesstokens/create", middleware.RequireAdminAuth(admin.CreateExternalAPIUser))
|
||||
|
||||
// Return the auto-update features that are supported for this instance.
|
||||
http.HandleFunc("/api/admin/update/options", middleware.RequireAdminAuth(admin.AutoUpdateOptions))
|
||||
|
||||
// Begin the auto update
|
||||
http.HandleFunc("/api/admin/update/start", middleware.RequireAdminAuth(admin.AutoUpdateStart))
|
||||
|
||||
// Force quit the service to restart it
|
||||
http.HandleFunc("/api/admin/update/forcequit", middleware.RequireAdminAuth(admin.AutoUpdateForceQuit))
|
||||
|
||||
// Send a system message to chat
|
||||
http.HandleFunc("/api/integrations/chat/system", middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessage))
|
||||
|
||||
// Send a system message to a single client
|
||||
http.HandleFunc(utils.RestEndpoint("/api/integrations/chat/system/client/{clientId}", middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendSystemMessageToConnectedClient)))
|
||||
|
||||
// Send a user message to chat *NO LONGER SUPPORTED
|
||||
http.HandleFunc("/api/integrations/chat/user", middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendUserMessage))
|
||||
|
||||
// Send a message to chat as a specific 3rd party bot/integration based on its access token
|
||||
http.HandleFunc("/api/integrations/chat/send", middleware.RequireExternalAPIAccessToken(user.ScopeCanSendChatMessages, admin.SendIntegrationChatMessage))
|
||||
|
||||
// Send a user action to chat
|
||||
http.HandleFunc("/api/integrations/chat/action", middleware.RequireExternalAPIAccessToken(user.ScopeCanSendSystemMessages, admin.SendChatAction))
|
||||
|
||||
// Hide chat message
|
||||
http.HandleFunc("/api/integrations/chat/messagevisibility", middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalUpdateMessageVisibility))
|
||||
|
||||
// Stream title
|
||||
http.HandleFunc("/api/integrations/streamtitle", middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalSetStreamTitle))
|
||||
|
||||
// Get chat history
|
||||
http.HandleFunc("/api/integrations/chat", middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, controllers.ExternalGetChatMessages))
|
||||
|
||||
// Connected clients
|
||||
http.HandleFunc("/api/integrations/clients", middleware.RequireExternalAPIAccessToken(user.ScopeHasAdminAccess, admin.ExternalGetConnectedChatClients))
|
||||
|
||||
// Logo path
|
||||
http.HandleFunc("/api/admin/config/logo", middleware.RequireAdminAuth(admin.SetLogo))
|
||||
|
||||
// Server tags
|
||||
http.HandleFunc("/api/admin/config/tags", middleware.RequireAdminAuth(admin.SetTags))
|
||||
|
||||
// ffmpeg
|
||||
http.HandleFunc("/api/admin/config/ffmpegpath", middleware.RequireAdminAuth(admin.SetFfmpegPath))
|
||||
|
||||
// Server http port
|
||||
http.HandleFunc("/api/admin/config/webserverport", middleware.RequireAdminAuth(admin.SetWebServerPort))
|
||||
|
||||
// Server http listen address
|
||||
http.HandleFunc("/api/admin/config/webserverip", middleware.RequireAdminAuth(admin.SetWebServerIP))
|
||||
|
||||
// Server rtmp port
|
||||
http.HandleFunc("/api/admin/config/rtmpserverport", middleware.RequireAdminAuth(admin.SetRTMPServerPort))
|
||||
|
||||
// Websocket host override
|
||||
http.HandleFunc("/api/admin/config/sockethostoverride", middleware.RequireAdminAuth(admin.SetSocketHostOverride))
|
||||
|
||||
// Custom video serving endpoint
|
||||
http.HandleFunc("/api/admin/config/videoservingendpoint", middleware.RequireAdminAuth(admin.SetVideoServingEndpoint))
|
||||
|
||||
// Is server marked as NSFW
|
||||
http.HandleFunc("/api/admin/config/nsfw", middleware.RequireAdminAuth(admin.SetNSFW))
|
||||
|
||||
// directory enabled
|
||||
http.HandleFunc("/api/admin/config/directoryenabled", middleware.RequireAdminAuth(admin.SetDirectoryEnabled))
|
||||
|
||||
// social handles
|
||||
http.HandleFunc("/api/admin/config/socialhandles", middleware.RequireAdminAuth(admin.SetSocialHandles))
|
||||
|
||||
// set the number of video segments and duration per segment in a playlist
|
||||
http.HandleFunc("/api/admin/config/video/streamlatencylevel", middleware.RequireAdminAuth(admin.SetStreamLatencyLevel))
|
||||
|
||||
// set an array of video output configurations
|
||||
http.HandleFunc("/api/admin/config/video/streamoutputvariants", middleware.RequireAdminAuth(admin.SetStreamOutputVariants))
|
||||
|
||||
// set s3 configuration
|
||||
http.HandleFunc("/api/admin/config/s3", middleware.RequireAdminAuth(admin.SetS3Configuration))
|
||||
|
||||
// set server url
|
||||
http.HandleFunc("/api/admin/config/serverurl", middleware.RequireAdminAuth(admin.SetServerURL))
|
||||
|
||||
// reset the YP registration
|
||||
http.HandleFunc("/api/admin/yp/reset", middleware.RequireAdminAuth(admin.ResetYPRegistration))
|
||||
|
||||
// set external action links
|
||||
http.HandleFunc("/api/admin/config/externalactions", middleware.RequireAdminAuth(admin.SetExternalActions))
|
||||
|
||||
// set custom style css
|
||||
http.HandleFunc("/api/admin/config/customstyles", middleware.RequireAdminAuth(admin.SetCustomStyles))
|
||||
|
||||
// set custom style javascript
|
||||
http.HandleFunc("/api/admin/config/customjavascript", middleware.RequireAdminAuth(admin.SetCustomJavascript))
|
||||
|
||||
// Video playback metrics
|
||||
http.HandleFunc("/api/admin/metrics/video", middleware.RequireAdminAuth(admin.GetVideoPlaybackMetrics))
|
||||
|
||||
// Is the viewer count hidden from viewers
|
||||
http.HandleFunc("/api/admin/config/hideviewercount", middleware.RequireAdminAuth(admin.SetHideViewerCount))
|
||||
|
||||
// set disabling of search indexing
|
||||
http.HandleFunc("/api/admin/config/disablesearchindexing", middleware.RequireAdminAuth(admin.SetDisableSearchIndexing))
|
||||
|
||||
// Inline chat moderation actions
|
||||
|
||||
// Update chat message visibility
|
||||
http.HandleFunc("/api/chat/messagevisibility", middleware.RequireUserModerationScopeAccesstoken(admin.UpdateMessageVisibility))
|
||||
|
||||
// Enable/disable a user
|
||||
http.HandleFunc("/api/chat/users/setenabled", middleware.RequireUserModerationScopeAccesstoken(admin.UpdateUserEnabled))
|
||||
|
||||
// Get a user's details
|
||||
http.HandleFunc("/api/moderation/chat/user/", middleware.RequireUserModerationScopeAccesstoken(moderation.GetUserDetails))
|
||||
|
||||
// Configure Federation features
|
||||
|
||||
// enable/disable federation features
|
||||
http.HandleFunc("/api/admin/config/federation/enable", middleware.RequireAdminAuth(admin.SetFederationEnabled))
|
||||
|
||||
// set if federation activities are private
|
||||
http.HandleFunc("/api/admin/config/federation/private", middleware.RequireAdminAuth(admin.SetFederationActivityPrivate))
|
||||
|
||||
// set if fediverse engagement appears in chat
|
||||
http.HandleFunc("/api/admin/config/federation/showengagement", middleware.RequireAdminAuth(admin.SetFederationShowEngagement))
|
||||
|
||||
// set local federated username
|
||||
http.HandleFunc("/api/admin/config/federation/username", middleware.RequireAdminAuth(admin.SetFederationUsername))
|
||||
|
||||
// set federated go live message
|
||||
http.HandleFunc("/api/admin/config/federation/livemessage", middleware.RequireAdminAuth(admin.SetFederationGoLiveMessage))
|
||||
|
||||
// Federation blocked domains
|
||||
http.HandleFunc("/api/admin/config/federation/blockdomains", middleware.RequireAdminAuth(admin.SetFederationBlockDomains))
|
||||
|
||||
// send a public message to the Fediverse from the server's user
|
||||
http.HandleFunc("/api/admin/federation/send", middleware.RequireAdminAuth(admin.SendFederatedMessage))
|
||||
|
||||
// Return federated activities
|
||||
http.HandleFunc("/api/admin/federation/actions", middleware.RequireAdminAuth(middleware.HandlePagination(admin.GetFederatedActions)))
|
||||
|
||||
// Prometheus metrics
|
||||
http.Handle("/api/admin/prometheus", middleware.RequireAdminAuth(func(rw http.ResponseWriter, r *http.Request) {
|
||||
promhttp.Handler().ServeHTTP(rw, r)
|
||||
}))
|
||||
|
||||
// Configure outbound notification channels.
|
||||
http.HandleFunc("/api/admin/config/notifications/discord", middleware.RequireAdminAuth(admin.SetDiscordNotificationConfiguration))
|
||||
http.HandleFunc("/api/admin/config/notifications/browser", middleware.RequireAdminAuth(admin.SetBrowserNotificationConfiguration))
|
||||
|
||||
// Auth
|
||||
|
||||
// Start auth flow
|
||||
http.HandleFunc("/api/auth/indieauth", middleware.RequireUserAccessToken(indieauth.StartAuthFlow))
|
||||
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))
|
||||
http.HandleFunc("/api/auth/fediverse/verify", fediverseauth.VerifyFediverseOTPRequest)
|
||||
// mount the api
|
||||
r.Mount("/api/", handler.New().Handler())
|
||||
|
||||
// ActivityPub has its own router
|
||||
activitypub.Start(data.GetDatastore())
|
||||
|
||||
// websocket
|
||||
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
|
||||
chat.HandleClientConnection(w, r)
|
||||
})
|
||||
|
||||
// Optional public static files
|
||||
http.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir(config.PublicFilesPath))))
|
||||
|
||||
port := config.WebServerPort
|
||||
ip := config.WebServerIP
|
||||
|
||||
h2s := &http2.Server{}
|
||||
|
||||
// Create a custom mux handler to intercept the /debug/vars endpoint.
|
||||
// This is a hack because Prometheus enables this endpoint by default
|
||||
// due to its use of expvar and we do not want this exposed.
|
||||
defaultMux := h2c.NewHandler(http.DefaultServeMux, h2s)
|
||||
h2s := &http2.Server{}
|
||||
http2Handler := h2c.NewHandler(r, h2s)
|
||||
m := http.NewServeMux()
|
||||
|
||||
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
@ -422,10 +79,13 @@ func Start() error {
|
||||
// Redirect /embed/chat
|
||||
http.Redirect(w, r, "/embed/chat/readonly", http.StatusTemporaryRedirect)
|
||||
} else {
|
||||
defaultMux.ServeHTTP(w, r)
|
||||
http2Handler.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
|
||||
port := config.WebServerPort
|
||||
ip := config.WebServerIP
|
||||
|
||||
compress, _ := httpcompression.DefaultAdapter() // Use the default configuration
|
||||
server := &http.Server{
|
||||
Addr: fmt.Sprintf("%s:%d", ip, port),
|
||||
@ -442,3 +102,43 @@ func Start() error {
|
||||
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
func addStaticFileEndpoints(r chi.Router) {
|
||||
// Images
|
||||
r.HandleFunc("/thumbnail.jpg", controllers.GetThumbnail)
|
||||
r.HandleFunc("/preview.gif", controllers.GetPreview)
|
||||
r.HandleFunc("/logo", controllers.GetLogo)
|
||||
// return a logo that's compatible with external social networks
|
||||
r.HandleFunc("/logo/external", controllers.GetCompatibleLogo)
|
||||
|
||||
// Custom Javascript
|
||||
r.HandleFunc("/customjavascript", controllers.ServeCustomJavascript)
|
||||
|
||||
// robots.txt
|
||||
r.HandleFunc("/robots.txt", controllers.GetRobotsDotTxt)
|
||||
|
||||
// Return a single emoji image.
|
||||
emojiDir := config.EmojiDir
|
||||
if !strings.HasSuffix(emojiDir, "*") {
|
||||
emojiDir += "*"
|
||||
}
|
||||
r.HandleFunc(emojiDir, controllers.GetCustomEmojiImage)
|
||||
|
||||
// WebFinger
|
||||
r.HandleFunc("/.well-known/webfinger", apControllers.WebfingerHandler)
|
||||
|
||||
// Host Metadata
|
||||
r.HandleFunc("/.well-known/host-meta", apControllers.HostMetaController)
|
||||
|
||||
// Nodeinfo v1
|
||||
r.HandleFunc("/.well-known/nodeinfo", apControllers.NodeInfoController)
|
||||
|
||||
// x-nodeinfo v2
|
||||
r.HandleFunc("/.well-known/x-nodeinfo2", apControllers.XNodeInfo2Controller)
|
||||
|
||||
// Nodeinfo v2
|
||||
r.HandleFunc("/nodeinfo/2.0", apControllers.NodeInfoV2Controller)
|
||||
|
||||
// Instance details
|
||||
r.HandleFunc("/api/v1/instance", apControllers.InstanceV1Controller)
|
||||
}
|
||||
|
41
spec/gen-api.sh
Executable file
41
spec/gen-api.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest
|
||||
|
||||
# setup
|
||||
package="generated"
|
||||
folderPath="handler/generated"
|
||||
specPath="spec/openapi.yaml"
|
||||
|
||||
# validate scripts are installed
|
||||
if ! command -v swagger-cli &> /dev/null
|
||||
then
|
||||
echo "Please install \`swagger-cli\` before running this script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v oapi-codegen &> /dev/null
|
||||
then
|
||||
echo "Please install \`oapi-codegen\` before running this script"
|
||||
echo "Hint: run \`go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@latest\` to install"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# validate schema
|
||||
swagger-cli validate $specPath
|
||||
if [ $? -ne 0 ];
|
||||
then
|
||||
echo "Open API specification is not valid"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# cleanup
|
||||
rm -r $folderPath
|
||||
mkdir -p $folderPath
|
||||
|
||||
# codegen
|
||||
oapi-codegen -generate types -o $folderPath/$package-types.gen.go -package $package $specPath
|
||||
oapi-codegen -generate "chi-server" -o $folderPath/$package.gen.go -package $package $specPath
|
||||
|
||||
# go
|
||||
go mod tidy
|
4413
spec/openapi.yaml
Normal file
4413
spec/openapi.yaml
Normal file
File diff suppressed because it is too large
Load Diff
128
static/metadata.html.tmpl
vendored
128
static/metadata.html.tmpl
vendored
@ -1,83 +1,85 @@
|
||||
<!doctype html>
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>{{.Name}}</title>
|
||||
<meta name="description" content="{{.Summary}}">
|
||||
<title>{{.Name}}</title>
|
||||
<meta name="description" content="{{.Summary}}">
|
||||
|
||||
<meta property="og:title" content="{{.Name}}">
|
||||
<meta property="og:site_name" content="{{.Name}}">
|
||||
<meta property="og:url" content="{{.RequestedURL}}">
|
||||
<meta property="og:description" content="{{.Summary}}">
|
||||
<meta property="og:type" content="video.other">
|
||||
<meta property="video:tag" content="{{.TagsString}}">
|
||||
<meta property="og:title" content="{{.Name}}">
|
||||
<meta property="og:site_name" content="{{.Name}}">
|
||||
<meta property="og:url" content="{{.RequestedURL}}">
|
||||
<meta property="og:description" content="{{.Summary}}">
|
||||
<meta property="og:type" content="video.other">
|
||||
<meta property="video:tag" content="{{.TagsString}}">
|
||||
|
||||
<meta property="og:image" content="{{.Thumbnail}}">
|
||||
<meta property="og:image:url" content="{{.Thumbnail}}">
|
||||
<meta property="og:image:alt" content="{{.Image}}">
|
||||
<meta property="og:image" content="{{.Thumbnail}}">
|
||||
<meta property="og:image:url" content="{{.Thumbnail}}">
|
||||
<meta property="og:image:alt" content="{{.Image}}">
|
||||
|
||||
<meta property="og:video" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="og:video:secure_url" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="og:video:height" content="315" />
|
||||
<meta property="og:video:width" content="560" />
|
||||
<meta property="og:video:type" content="text/html" />
|
||||
<meta property="og:video:actor" content="{{.Name}}" />
|
||||
<meta property="og:video" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="og:video:secure_url" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="og:video:height" content="315" />
|
||||
<meta property="og:video:width" content="560" />
|
||||
<meta property="og:video:type" content="text/html" />
|
||||
<meta property="og:video:actor" content="{{.Name}}" />
|
||||
|
||||
<meta property="twitter:title" content="{{.Name}}">
|
||||
<meta property="twitter:url" content="{{.RequestedURL}}">
|
||||
<meta property="twitter:description" content="{{.Summary}}">
|
||||
<meta property="twitter:image" content="{{.Image}}">
|
||||
<meta property="twitter:card" content="player" />
|
||||
<meta property="twitter:player" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="twitter:player:width" content="560" />
|
||||
<meta property="twitter:player:height" content="315" />
|
||||
<meta property="twitter:title" content="{{.Name}}">
|
||||
<meta property="twitter:url" content="{{.RequestedURL}}">
|
||||
<meta property="twitter:description" content="{{.Summary}}">
|
||||
<meta property="twitter:image" content="{{.Image}}">
|
||||
<meta property="twitter:card" content="player" />
|
||||
<meta property="twitter:player" content='{{.RequestedURL}}embed/video' />
|
||||
<meta property="twitter:player:width" content="560" />
|
||||
<meta property="twitter:player:height" content="315" />
|
||||
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/img/favicon/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/img/favicon/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/img/favicon/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/img/favicon/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/img/favicon/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/img/favicon/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/img/favicon/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/img/favicon/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/favicon/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/img/favicon/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/img/favicon/apple-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/img/favicon/apple-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/img/favicon/apple-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/img/favicon/apple-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/img/favicon/apple-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/img/favicon/apple-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/img/favicon/apple-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/img/favicon/apple-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/img/favicon/apple-icon-180x180.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/img/favicon/android-icon-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="/img/favicon/favicon-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon/favicon-96x96.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16.png">
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
|
||||
<link rel="authorization_endpoint" href="/api/auth/provider/indieauth">
|
||||
<link rel="authorization_endpoint" href="/api/auth/provider/indieauth">
|
||||
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="/img/favicon/ms-icon-144x144.png">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="msapplication-TileImage" content="/img/favicon/ms-icon-144x144.png">
|
||||
<meta name="theme-color" content="#ffffff">
|
||||
</head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{.Name}}</h1>
|
||||
|
||||
<body>
|
||||
<h1>{{.Name}}</h1>
|
||||
<center>
|
||||
<img src="{{.Thumbnail}}" width=10% alt="Live stream logo or thumbnail"/>
|
||||
</center>
|
||||
|
||||
<center>
|
||||
<img src="{{.Thumbnail}}" width=10% />
|
||||
</center>
|
||||
<h3>{{.Summary}}</h3>
|
||||
|
||||
<h3>{{.Summary}}</h3>
|
||||
<ul>
|
||||
{{range .Tags}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
{{range .Tags}}
|
||||
<li>{{.}}</li>
|
||||
{{end}}
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
<h3>Links for {{.Name}}:</h3>
|
||||
|
||||
<h3>Links for {{.Name}}:</h3>
|
||||
<ul>
|
||||
{{range .SocialHandles}}
|
||||
<li><a href="{{.URL}}" rel="me">{{.Platform}}</a></li>
|
||||
{{end}}
|
||||
</ul>
|
||||
|
||||
{{range .SocialHandles}}
|
||||
<li><a href="{{.URL}}">{{.Platform}}</a></li>
|
||||
{{end}}
|
||||
|
||||
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
BIN
static/offline-v2.ts
vendored
Normal file
BIN
static/offline-v2.ts
vendored
Normal file
Binary file not shown.
BIN
static/offline.tsclip
vendored
BIN
static/offline.tsclip
vendored
Binary file not shown.
4
static/static.go
vendored
4
static/static.go
vendored
@ -51,12 +51,12 @@ func GetWebIndexTemplate() (*template.Template, error) {
|
||||
return tmpl, err
|
||||
}
|
||||
|
||||
//go:embed offline.tsclip
|
||||
//go:embed offline-v2.ts
|
||||
var offlineVideoSegment []byte
|
||||
|
||||
// GetOfflineSegment will return the offline video segment data.
|
||||
func GetOfflineSegment() []byte {
|
||||
return getFileSystemStaticFileOrDefault("offline.tsclip", offlineVideoSegment)
|
||||
return getFileSystemStaticFileOrDefault("offline-v2.ts", offlineVideoSegment)
|
||||
}
|
||||
|
||||
//go:embed img/logo.png
|
||||
|
6
static/web/404.html
vendored
6
static/web/404.html
vendored
File diff suppressed because one or more lines are too long
6
static/web/404/index.html
vendored
6
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 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1008],{98696:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M816 768h-24V428c0-141.1-104.3-257.7-240-277.1V112c0-22.1-17.9-40-40-40s-40 17.9-40 40v38.9c-135.7 19.4-240 136-240 277.1v340h-24c-17.7 0-32 14.3-32 32v32c0 4.4 3.6 8 8 8h216c0 61.8 50.2 112 112 112s112-50.2 112-112h216c4.4 0 8-3.6 8-8v-32c0-17.7-14.3-32-32-32zM512 888c-26.5 0-48-21.5-48-48h96c0 26.5-21.5 48-48 48zM304 768V428c0-55.6 21.6-107.8 60.9-147.1S456.4 220 512 220c55.6 0 107.8 21.6 147.1 60.9S720 372.4 720 428v340H304z"}}]},name:"bell",theme:"outlined"}},11008:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var u=_interopRequireDefault(r(25594));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}t.default=u,e.exports=u},25594:function(e,t,r){var u=r(64836),a=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=u(r(42122)),l=_interopRequireWildcard(r(67294)),i=u(r(98696)),c=u(r(92074));function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(_getRequireWildcardCache=function(e){return e?r:t})(e)}function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var r=_getRequireWildcardCache(t);if(r&&r.has(e))return r.get(e);var u={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&Object.prototype.hasOwnProperty.call(e,l)){var i=n?Object.getOwnPropertyDescriptor(e,l):null;i&&(i.get||i.set)?Object.defineProperty(u,l,i):u[l]=e[l]}return u.default=e,r&&r.set(e,u),u}var BellOutlined=function(e,t){return l.createElement(c.default,(0,n.default)((0,n.default)({},e),{},{ref:t,icon:i.default}))};BellOutlined.displayName="BellOutlined";var f=l.forwardRef(BellOutlined);t.default=f}}]);
|
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1010],{90034:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:function(e,t){return{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M180 292h80v440h-80zm369 180h-74a3 3 0 00-3 3v74a3 3 0 003 3h74a3 3 0 003-3v-74a3 3 0 00-3-3zm215-108h80v296h-80z",fill:t}},{tag:"path",attrs:{d:"M904 296h-66v-96c0-4.4-3.6-8-8-8h-52c-4.4 0-8 3.6-8 8v96h-66c-4.4 0-8 3.6-8 8v416c0 4.4 3.6 8 8 8h66v96c0 4.4 3.6 8 8 8h52c4.4 0 8-3.6 8-8v-96h66c4.4 0 8-3.6 8-8V304c0-4.4-3.6-8-8-8zm-60 364h-80V364h80v296zM612 404h-66V232c0-4.4-3.6-8-8-8h-52c-4.4 0-8 3.6-8 8v172h-66c-4.4 0-8 3.6-8 8v200c0 4.4 3.6 8 8 8h66v172c0 4.4 3.6 8 8 8h52c4.4 0 8-3.6 8-8V620h66c4.4 0 8-3.6 8-8V412c0-4.4-3.6-8-8-8zm-60 145a3 3 0 01-3 3h-74a3 3 0 01-3-3v-74a3 3 0 013-3h74a3 3 0 013 3v74zM320 224h-66v-56c0-4.4-3.6-8-8-8h-52c-4.4 0-8 3.6-8 8v56h-66c-4.4 0-8 3.6-8 8v560c0 4.4 3.6 8 8 8h66v56c0 4.4 3.6 8 8 8h52c4.4 0 8-3.6 8-8v-56h66c4.4 0 8-3.6 8-8V232c0-4.4-3.6-8-8-8zm-60 508h-80V292h80v440z",fill:e}}]}},name:"sliders",theme:"twotone"}},71010:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=_interopRequireDefault(r(54626));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}t.default=a,e.exports=a},54626:function(e,t,r){var a=r(64836),c=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=a(r(42122)),u=_interopRequireWildcard(r(67294)),i=a(r(90034)),o=a(r(92074));function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(_getRequireWildcardCache=function(e){return e?r:t})(e)}function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==c(e)&&"function"!=typeof e)return{default:e};var r=_getRequireWildcardCache(t);if(r&&r.has(e))return r.get(e);var a={},n=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var u in e)if("default"!==u&&Object.prototype.hasOwnProperty.call(e,u)){var i=n?Object.getOwnPropertyDescriptor(e,u):null;i&&(i.get||i.set)?Object.defineProperty(a,u,i):a[u]=e[u]}return a.default=e,r&&r.set(e,a),a}var SlidersTwoTone=function(e,t){return u.createElement(o.default,(0,n.default)((0,n.default)({},e),{},{ref:t,icon:i.default}))};SlidersTwoTone.displayName="SlidersTwoTone";var l=u.forwardRef(SlidersTwoTone);t.default=l}}]);
|
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1027.6ff58c73d32252d3.js
vendored
Normal file
1
static/web/_next/static/chunks/1027.6ff58c73d32252d3.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1027],{96121:function(e,r,o){function t(e){var r={as:"keyword",do:"keyword",else:"keyword",end:"keyword",exception:"keyword",fun:"keyword",functor:"keyword",if:"keyword",in:"keyword",include:"keyword",let:"keyword",of:"keyword",open:"keyword",rec:"keyword",struct:"keyword",then:"keyword",type:"keyword",val:"keyword",while:"keyword",with:"keyword"},o=e.extraWords||{};for(var t in o)o.hasOwnProperty(t)&&(r[t]=e.extraWords[t]);var n=[];for(var i in r)n.push(i);function d(o,t){var n=o.next();if('"'===n)return t.tokenize=k,t.tokenize(o,t);if("{"===n&&o.eat("|"))return t.longString=!0,t.tokenize=y,t.tokenize(o,t);if("("===n&&o.match(/^\*(?!\))/))return t.commentLevel++,t.tokenize=w,t.tokenize(o,t);if("~"===n||"?"===n)return o.eatWhile(/\w/),"variableName.special";if("`"===n)return o.eatWhile(/\w/),"quote";if("/"===n&&e.slashComments&&o.eat("/"))return o.skipToEnd(),"comment";if(/\d/.test(n))return"0"===n&&o.eat(/[bB]/)&&o.eatWhile(/[01]/),"0"===n&&o.eat(/[xX]/)&&o.eatWhile(/[0-9a-fA-F]/),"0"===n&&o.eat(/[oO]/)?o.eatWhile(/[0-7]/):(o.eatWhile(/[\d_]/),o.eat(".")&&o.eatWhile(/[\d]/),o.eat(/[eE]/)&&o.eatWhile(/[\d\-+]/)),"number";if(/[+\-*&%=<>!?|@\.~:]/.test(n))return"operator";if(/[\w\xa1-\uffff]/.test(n)){o.eatWhile(/[\w\xa1-\uffff]/);var i=o.current();return r.hasOwnProperty(i)?r[i]:"variable"}return null}function k(e,r){for(var o,t=!1,n=!1;null!=(o=e.next());){if('"'===o&&!n){t=!0;break}n=!n&&"\\"===o}return t&&!n&&(r.tokenize=d),"string"}function w(e,r){for(var o,t;r.commentLevel>0&&null!=(t=e.next());)"("===o&&"*"===t&&r.commentLevel++,"*"===o&&")"===t&&r.commentLevel--,o=t;return r.commentLevel<=0&&(r.tokenize=d),"comment"}function y(e,r){for(var o,t;r.longString&&null!=(t=e.next());)"|"===o&&"}"===t&&(r.longString=!1),o=t;return r.longString||(r.tokenize=d),"string"}return{startState:function(){return{tokenize:d,commentLevel:0,longString:!1}},token:function(e,r){return e.eatSpace()?null:r.tokenize(e,r)},languageData:{autocomplete:n,commentTokens:{line:e.slashComments?"//":void 0,block:{open:"(*",close:"*)"}}}}}o.r(r),o.d(r,{fSharp:function(){return i},oCaml:function(){return n},sml:function(){return d}});let n=t({name:"ocaml",extraWords:{and:"keyword",assert:"keyword",begin:"keyword",class:"keyword",constraint:"keyword",done:"keyword",downto:"keyword",external:"keyword",function:"keyword",initializer:"keyword",lazy:"keyword",match:"keyword",method:"keyword",module:"keyword",mutable:"keyword",new:"keyword",nonrec:"keyword",object:"keyword",private:"keyword",sig:"keyword",to:"keyword",try:"keyword",value:"keyword",virtual:"keyword",when:"keyword",raise:"builtin",failwith:"builtin",true:"builtin",false:"builtin",asr:"builtin",land:"builtin",lor:"builtin",lsl:"builtin",lsr:"builtin",lxor:"builtin",mod:"builtin",or:"builtin",raise_notrace:"builtin",trace:"builtin",exit:"builtin",print_string:"builtin",print_endline:"builtin",int:"type",float:"type",bool:"type",char:"type",string:"type",unit:"type",List:"builtin"}}),i=t({name:"fsharp",extraWords:{abstract:"keyword",assert:"keyword",base:"keyword",begin:"keyword",class:"keyword",default:"keyword",delegate:"keyword","do!":"keyword",done:"keyword",downcast:"keyword",downto:"keyword",elif:"keyword",extern:"keyword",finally:"keyword",for:"keyword",function:"keyword",global:"keyword",inherit:"keyword",inline:"keyword",interface:"keyword",internal:"keyword",lazy:"keyword","let!":"keyword",match:"keyword",member:"keyword",module:"keyword",mutable:"keyword",namespace:"keyword",new:"keyword",null:"keyword",override:"keyword",private:"keyword",public:"keyword","return!":"keyword",return:"keyword",select:"keyword",static:"keyword",to:"keyword",try:"keyword",upcast:"keyword","use!":"keyword",use:"keyword",void:"keyword",when:"keyword","yield!":"keyword",yield:"keyword",atomic:"keyword",break:"keyword",checked:"keyword",component:"keyword",const:"keyword",constraint:"keyword",constructor:"keyword",continue:"keyword",eager:"keyword",event:"keyword",external:"keyword",fixed:"keyword",method:"keyword",mixin:"keyword",object:"keyword",parallel:"keyword",process:"keyword",protected:"keyword",pure:"keyword",sealed:"keyword",tailcall:"keyword",trait:"keyword",virtual:"keyword",volatile:"keyword",List:"builtin",Seq:"builtin",Map:"builtin",Set:"builtin",Option:"builtin",int:"builtin",string:"builtin",not:"builtin",true:"builtin",false:"builtin",raise:"builtin",failwith:"builtin"},slashComments:!0}),d=t({name:"sml",extraWords:{abstype:"keyword",and:"keyword",andalso:"keyword",case:"keyword",datatype:"keyword",fn:"keyword",handle:"keyword",infix:"keyword",infixr:"keyword",local:"keyword",nonfix:"keyword",op:"keyword",orelse:"keyword",raise:"keyword",withtype:"keyword",eqtype:"keyword",sharing:"keyword",sig:"keyword",signature:"keyword",structure:"keyword",where:"keyword",true:"keyword",false:"keyword",int:"builtin",real:"builtin",string:"builtin",char:"builtin",bool:"builtin"},slashComments:!0})}}]);
|
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([[1053],{21053:function(e,t,r){function mkZ80(e){e?(t=/^(exx?|(ld|cp)([di]r?)?|[lp]ea|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|[de]i|halt|im|in([di]mr?|ir?|irx|2r?)|ot(dmr?|[id]rx|imr?)|out(0?|[di]r?|[di]2r?)|tst(io)?|slp)(\.([sl]?i)?[sl])?\b/i,r=/^(((call|j[pr]|rst|ret[in]?)(\.([sl]?i)?[sl])?)|(rs|st)mix)\b/i):(t=/^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i,r=/^(call|j[pr]|ret[in]?|b_?(call|jump))\b/i);var t,r,n=/^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i,i=/^(n?[zc]|p[oe]?|m)\b/i,l=/^([hl][xy]|i[xy][hl]|slia|sll)\b/i,a=/^([\da-f]+h|[0-7]+o|[01]+b|\d+d?)\b/i;return{name:"z80",startState:function(){return{context:0}},token:function(s,c){var u;if(s.column()||(c.context=0),s.eatSpace())return null;if(s.eatWhile(/\w/)){if(e&&s.eat(".")&&s.eatWhile(/\w/),u=s.current(),s.indentation()){if((1==c.context||4==c.context)&&n.test(u))return c.context=4,"variable";if(2==c.context&&i.test(u))return c.context=4,"variableName.special";if(t.test(u))return c.context=1,"keyword";if(r.test(u))return c.context=2,"keyword";if(4==c.context&&a.test(u))return"number";if(l.test(u))return"error"}else if(s.match(a))return"number"}else if(s.eat(";"))return s.skipToEnd(),"comment";else if(s.eat('"')){for(;(u=s.next())&&'"'!=u;)"\\"==u&&s.next();return"string"}else if(s.eat("'")){if(s.match(/\\?.'/))return"number"}else if(s.eat(".")||s.sol()&&s.eat("#")){if(c.context=5,s.eatWhile(/\w/))return"def"}else if(s.eat("$")){if(s.eatWhile(/[\da-f]/i))return"number"}else if(s.eat("%")){if(s.eatWhile(/[01]/))return"number"}else s.next();return null}}}r.r(t),r.d(t,{ez80:function(){return i},z80:function(){return n}});let n=mkZ80(!1),i=mkZ80(!0)}}]);
|
1
static/web/_next/static/chunks/1053.adb29a47c34b267a.js
vendored
Normal file
1
static/web/_next/static/chunks/1053.adb29a47c34b267a.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1053],{21053:function(e,t,r){function n(e){e?(t=/^(exx?|(ld|cp)([di]r?)?|[lp]ea|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|[de]i|halt|im|in([di]mr?|ir?|irx|2r?)|ot(dmr?|[id]rx|imr?)|out(0?|[di]r?|[di]2r?)|tst(io)?|slp)(\.([sl]?i)?[sl])?\b/i,r=/^(((call|j[pr]|rst|ret[in]?)(\.([sl]?i)?[sl])?)|(rs|st)mix)\b/i):(t=/^(exx?|(ld|cp|in)([di]r?)?|pop|push|ad[cd]|cpl|daa|dec|inc|neg|sbc|sub|and|bit|[cs]cf|x?or|res|set|r[lr]c?a?|r[lr]d|s[lr]a|srl|djnz|nop|rst|[de]i|halt|im|ot[di]r|out[di]?)\b/i,r=/^(call|j[pr]|ret[in]?|b_?(call|jump))\b/i);var t,r,n=/^(af?|bc?|c|de?|e|hl?|l|i[xy]?|r|sp)\b/i,i=/^(n?[zc]|p[oe]?|m)\b/i,l=/^([hl][xy]|i[xy][hl]|slia|sll)\b/i,a=/^([\da-f]+h|[0-7]+o|[01]+b|\d+d?)\b/i;return{name:"z80",startState:function(){return{context:0}},token:function(s,c){var u;if(s.column()||(c.context=0),s.eatSpace())return null;if(s.eatWhile(/\w/)){if(e&&s.eat(".")&&s.eatWhile(/\w/),u=s.current(),s.indentation()){if((1==c.context||4==c.context)&&n.test(u))return c.context=4,"variable";if(2==c.context&&i.test(u))return c.context=4,"variableName.special";if(t.test(u))return c.context=1,"keyword";if(r.test(u))return c.context=2,"keyword";if(4==c.context&&a.test(u))return"number";if(l.test(u))return"error"}else if(s.match(a))return"number"}else if(s.eat(";"))return s.skipToEnd(),"comment";else if(s.eat('"')){for(;(u=s.next())&&'"'!=u;)"\\"==u&&s.next();return"string"}else if(s.eat("'")){if(s.match(/\\?.'/))return"number"}else if(s.eat(".")||s.sol()&&s.eat("#")){if(c.context=5,s.eatWhile(/\w/))return"def"}else if(s.eat("$")){if(s.eatWhile(/[\da-f]/i))return"number"}else if(s.eat("%")){if(s.eatWhile(/[01]/))return"number"}else s.next();return null}}}r.r(t),r.d(t,{ez80:function(){return l},z80:function(){return i}});let i=n(!1),l=n(!0)}}]);
|
1
static/web/_next/static/chunks/108.1167392b63feba04.js
vendored
Normal file
1
static/web/_next/static/chunks/108.1167392b63feba04.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[108],{65089:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z"}}]},name:"lock",theme:"outlined"}},30108:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n,u=(n=r(34811))&&n.__esModule?n:{default:n};t.default=u,e.exports=u},34811:function(e,t,r){var n=r(64836),u=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=n(r(42122)),f=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=u(e)&&"function"!=typeof e)return{default:e};var r=l(void 0);if(r&&r.has(e))return r.get(e);var n={__proto__:null},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&({}).hasOwnProperty.call(e,f)){var o=a?Object.getOwnPropertyDescriptor(e,f):null;o&&(o.get||o.set)?Object.defineProperty(n,f,o):n[f]=e[f]}return n.default=e,r&&r.set(e,n),n}(r(67294)),o=n(r(65089)),c=n(r(3908));function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(l=function(e){return e?r:t})(e)}var i=f.forwardRef(function(e,t){return f.createElement(c.default,(0,a.default)((0,a.default)({},e),{},{ref:t,icon:o.default}))});t.default=i}}]);
|
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1084],{41084:function(e,n,t){t.r(n),t.d(n,{jinja2:function(){return c}});var a=["and","as","block","endblock","by","cycle","debug","else","elif","extends","filter","endfilter","firstof","do","for","endfor","if","endif","ifchanged","endifchanged","ifequal","endifequal","ifnotequal","set","raw","endraw","endifnotequal","in","include","load","not","now","or","parsed","regroup","reversed","spaceless","call","endcall","macro","endmacro","endspaceless","ssi","templatetag","openblock","closeblock","openvariable","closevariable","without","context","openbrace","closebrace","opencomment","closecomment","widthratio","url","with","endwith","get_current_language","trans","endtrans","noop","blocktrans","endblocktrans","get_available_languages","get_current_language_bidi","pluralize","autoescape","endautoescape"],i=/^[+\-*&%=<>!?|~^]/,r=/^[:\[\(\{]/,o=["true","false"],s=/^(\d[+\-\*\/])?\d+(\.\d+)?/;function tokenBase(e,n){var t=e.peek();if(n.incomment)return e.skipTo("#}")?(e.eatWhile(/\#|}/),n.incomment=!1):e.skipToEnd(),"comment";if(n.intag){if(n.operator){if(n.operator=!1,e.match(o))return"atom";if(e.match(s))return"number"}if(n.sign){if(n.sign=!1,e.match(o))return"atom";if(e.match(s))return"number"}if(n.instring)return t==n.instring&&(n.instring=!1),e.next(),"string";if("'"==t||'"'==t)return n.instring=t,e.next(),"string";if(n.inbraces>0&&")"==t)e.next(),n.inbraces--;else if("("==t)e.next(),n.inbraces++;else if(n.inbrackets>0&&"]"==t)e.next(),n.inbrackets--;else if("["==t)e.next(),n.inbrackets++;else if(!n.lineTag&&(e.match(n.intag+"}")||e.eat("-")&&e.match(n.intag+"}")))return n.intag=!1,"tag";else if(e.match(i))return n.operator=!0,"operator";else if(e.match(r))n.sign=!0;else{if(1==e.column()&&n.lineTag&&e.match(a))return"keyword";if(e.eat(" ")||e.sol()){if(e.match(a))return"keyword";if(e.match(o))return"atom";if(e.match(s))return"number";e.sol()&&e.next()}else e.next()}return"variable"}if(e.eat("{")){if(e.eat("#"))return n.incomment=!0,e.skipTo("#}")?(e.eatWhile(/\#|}/),n.incomment=!1):e.skipToEnd(),"comment";if(t=e.eat(/\{|%/))return n.intag=t,n.inbraces=0,n.inbrackets=0,"{"==t&&(n.intag="}"),e.eat("-"),"tag"}else if(e.eat("#")){if("#"==e.peek())return e.skipToEnd(),"comment";if(!e.eol())return n.intag=!0,n.lineTag=!0,n.inbraces=0,n.inbrackets=0,"tag"}e.next()}a=RegExp("(("+a.join(")|(")+"))\\b"),o=RegExp("(("+o.join(")|(")+"))\\b");let c={name:"jinja2",startState:function(){return{tokenize:tokenBase,inbrackets:0,inbraces:0}},token:function(e,n){var t=n.tokenize(e,n);return e.eol()&&n.lineTag&&!n.instring&&0==n.inbraces&&0==n.inbrackets&&(n.intag=!1,n.lineTag=!1),t},languageData:{commentTokens:{block:{open:"{#",close:"#}",line:"##"}}}}}}]);
|
1
static/web/_next/static/chunks/1084.8bd09a422bf924f1.js
vendored
Normal file
1
static/web/_next/static/chunks/1084.8bd09a422bf924f1.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1084],{41084:function(e,n,t){t.r(n),t.d(n,{jinja2:function(){return l}});var i=["and","as","block","endblock","by","cycle","debug","else","elif","extends","filter","endfilter","firstof","do","for","endfor","if","endif","ifchanged","endifchanged","ifequal","endifequal","ifnotequal","set","raw","endraw","endifnotequal","in","include","load","not","now","or","parsed","regroup","reversed","spaceless","call","endcall","macro","endmacro","endspaceless","ssi","templatetag","openblock","closeblock","openvariable","closevariable","without","context","openbrace","closebrace","opencomment","closecomment","widthratio","url","with","endwith","get_current_language","trans","endtrans","noop","blocktrans","endblocktrans","get_available_languages","get_current_language_bidi","pluralize","autoescape","endautoescape"],a=/^[+\-*&%=<>!?|~^]/,r=/^[:\[\(\{]/,o=["true","false"],c=/^(\d[+\-\*\/])?\d+(\.\d+)?/;function s(e,n){var t=e.peek();if(n.incomment)return e.skipTo("#}")?(e.eatWhile(/\#|}/),n.incomment=!1):e.skipToEnd(),"comment";if(n.intag){if(n.operator){if(n.operator=!1,e.match(o))return"atom";if(e.match(c))return"number"}if(n.sign){if(n.sign=!1,e.match(o))return"atom";if(e.match(c))return"number"}if(n.instring)return t==n.instring&&(n.instring=!1),e.next(),"string";if("'"==t||'"'==t)return n.instring=t,e.next(),"string";if(n.inbraces>0&&")"==t)e.next(),n.inbraces--;else if("("==t)e.next(),n.inbraces++;else if(n.inbrackets>0&&"]"==t)e.next(),n.inbrackets--;else if("["==t)e.next(),n.inbrackets++;else if(!n.lineTag&&(e.match(n.intag+"}")||e.eat("-")&&e.match(n.intag+"}")))return n.intag=!1,"tag";else if(e.match(a))return n.operator=!0,"operator";else if(e.match(r))n.sign=!0;else{if(1==e.column()&&n.lineTag&&e.match(i))return"keyword";if(e.eat(" ")||e.sol()){if(e.match(i))return"keyword";if(e.match(o))return"atom";if(e.match(c))return"number";e.sol()&&e.next()}else e.next()}return"variable"}if(e.eat("{")){if(e.eat("#"))return n.incomment=!0,e.skipTo("#}")?(e.eatWhile(/\#|}/),n.incomment=!1):e.skipToEnd(),"comment";if(t=e.eat(/\{|%/))return n.intag=t,n.inbraces=0,n.inbrackets=0,"{"==t&&(n.intag="}"),e.eat("-"),"tag"}else if(e.eat("#")){if("#"==e.peek())return e.skipToEnd(),"comment";if(!e.eol())return n.intag=!0,n.lineTag=!0,n.inbraces=0,n.inbrackets=0,"tag"}e.next()}i=RegExp("(("+i.join(")|(")+"))\\b"),o=RegExp("(("+o.join(")|(")+"))\\b");let l={name:"jinja2",startState:function(){return{tokenize:s,inbrackets:0,inbraces:0}},token:function(e,n){var t=n.tokenize(e,n);return e.eol()&&n.lineTag&&!n.instring&&0==n.inbraces&&0==n.inbrackets&&(n.intag=!1,n.lineTag=!1),t},languageData:{commentTokens:{block:{open:"{#",close:"#}",line:"##"}}}}}}]);
|
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1189.11bd4390e96fb8ce.js
vendored
Normal file
1
static/web/_next/static/chunks/1189.11bd4390e96fb8ce.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1189],{92262:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M881.7 187.4l-45.1-45.1a8.03 8.03 0 00-11.3 0L667.8 299.9l-54.7-54.7a7.94 7.94 0 00-13.5 4.7L576.1 439c-.6 5.2 3.7 9.5 8.9 8.9l189.2-23.5c6.6-.8 9.3-8.8 4.7-13.5l-54.7-54.7 157.6-157.6c3-3 3-8.1-.1-11.2zM439 576.1l-189.2 23.5c-6.6.8-9.3 8.9-4.7 13.5l54.7 54.7-157.5 157.5a8.03 8.03 0 000 11.3l45.1 45.1c3.1 3.1 8.2 3.1 11.3 0l157.6-157.6 54.7 54.7a7.94 7.94 0 0013.5-4.7L447.9 585a7.9 7.9 0 00-8.9-8.9z"}}]},name:"shrink",theme:"outlined"}},91189:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a,n=(a=r(85e3))&&a.__esModule?a:{default:a};t.default=n,e.exports=n},85e3:function(e,t,r){var a=r(64836),n=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var u=a(r(42122)),l=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=n(e)&&"function"!=typeof e)return{default:e};var r=c(void 0);if(r&&r.has(e))return r.get(e);var a={__proto__:null},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var l in e)if("default"!==l&&({}).hasOwnProperty.call(e,l)){var f=u?Object.getOwnPropertyDescriptor(e,l):null;f&&(f.get||f.set)?Object.defineProperty(a,l,f):a[l]=e[l]}return a.default=e,r&&r.set(e,a),a}(r(67294)),f=a(r(92262)),o=a(r(3908));function c(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(c=function(e){return e?r:t})(e)}var i=l.forwardRef(function(e,t){return l.createElement(o.default,(0,u.default)((0,u.default)({},e),{},{ref:t,icon:f.default}))});t.default=i}}]);
|
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1390.3779e22e0f3b461d.js
vendored
Normal file
1
static/web/_next/static/chunks/1390.3779e22e0f3b461d.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1446.729b459281b981b9.js
vendored
Normal file
1
static/web/_next/static/chunks/1446.729b459281b981b9.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1446],{61446:function(e,t,n){n.r(t),n.d(t,{commonLisp:function(){return d}});var r,o=/^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/,l=/^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/,i=/^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/,a=/[^\s'`,@()\[\]";]/;function c(e){for(var t;t=e.next();)if("\\"==t)e.next();else if(!a.test(t)){e.backUp(1);break}return e.current()}function u(e,t){if(e.eatSpace())return r="ws",null;if(e.match(i))return"number";var n=e.next();if("\\"==n&&(n=e.next()),'"'==n)return(t.tokenize=s)(e,t);if("("==n)return r="open","bracket";if(")"==n||"]"==n)return r="close","bracket";if(";"==n)return e.skipToEnd(),r="ws","comment";if(/['`,@]/.test(n))return null;if("|"==n)return e.skipTo("|")?(e.next(),"variableName"):(e.skipToEnd(),"error");if("#"==n){var n=e.next();if("("==n)return r="open","bracket";if(/[+\-=\.']/.test(n))return null;if(/\d/.test(n)&&e.match(/^\d*#/))return null;if("|"==n)return(t.tokenize=f)(e,t);else if(":"==n)return c(e),"meta";else if("\\"==n)return e.next(),c(e),"string.special";else return"error"}else{var a=c(e);return"."==a?null:(r="symbol","nil"==a||"t"==a||":"==a.charAt(0))?"atom":"open"==t.lastType&&(o.test(a)||l.test(a))?"keyword":"&"==a.charAt(0)?"variableName.special":"variableName"}}function s(e,t){for(var n,r=!1;n=e.next();){if('"'==n&&!r){t.tokenize=u;break}r=!r&&"\\"==n}return"string"}function f(e,t){for(var n,o;n=e.next();){if("#"==n&&"|"==o){t.tokenize=u;break}o=n}return r="ws","comment"}let d={name:"commonlisp",startState:function(){return{ctx:{prev:null,start:0,indentTo:0},lastType:null,tokenize:u}},token:function(e,t){e.sol()&&"number"!=typeof t.ctx.indentTo&&(t.ctx.indentTo=t.ctx.start+1),r=null;var n=t.tokenize(e,t);return"ws"!=r&&(null==t.ctx.indentTo?"symbol"==r&&l.test(e.current())?t.ctx.indentTo=t.ctx.start+e.indentUnit:t.ctx.indentTo="next":"next"==t.ctx.indentTo&&(t.ctx.indentTo=e.column()),t.lastType=r),"open"==r?t.ctx={prev:t.ctx,start:e.column(),indentTo:null}:"close"==r&&(t.ctx=t.ctx.prev||t.ctx),n},indent:function(e){var t=e.ctx.indentTo;return"number"==typeof t?t:e.ctx.start+1},languageData:{commentTokens:{line:";;",block:{open:"#|",close:"|#"}},closeBrackets:{brackets:["(","[","{",'"']}}}}}]);
|
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1446],{61446:function(e,t,n){n.r(t),n.d(t,{commonLisp:function(){return c}});var r,o=/^(block|let*|return-from|catch|load-time-value|setq|eval-when|locally|symbol-macrolet|flet|macrolet|tagbody|function|multiple-value-call|the|go|multiple-value-prog1|throw|if|progn|unwind-protect|labels|progv|let|quote)$/,a=/^with|^def|^do|^prog|case$|^cond$|bind$|when$|unless$/,i=/^(?:[+\-]?(?:\d+|\d*\.\d+)(?:[efd][+\-]?\d+)?|[+\-]?\d+(?:\/[+\-]?\d+)?|#b[+\-]?[01]+|#o[+\-]?[0-7]+|#x[+\-]?[\da-f]+)/,l=/[^\s'`,@()\[\]";]/;function readSym(e){for(var t;t=e.next();)if("\\"==t)e.next();else if(!l.test(t)){e.backUp(1);break}return e.current()}function base(e,t){if(e.eatSpace())return r="ws",null;if(e.match(i))return"number";var n=e.next();if("\\"==n&&(n=e.next()),'"'==n)return(t.tokenize=inString)(e,t);if("("==n)return r="open","bracket";if(")"==n||"]"==n)return r="close","bracket";if(";"==n)return e.skipToEnd(),r="ws","comment";if(/['`,@]/.test(n))return null;if("|"==n)return e.skipTo("|")?(e.next(),"variableName"):(e.skipToEnd(),"error");if("#"==n){var n=e.next();if("("==n)return r="open","bracket";if(/[+\-=\.']/.test(n))return null;if(/\d/.test(n)&&e.match(/^\d*#/))return null;if("|"==n)return(t.tokenize=inComment)(e,t);else if(":"==n)return readSym(e),"meta";else if("\\"==n)return e.next(),readSym(e),"string.special";else return"error"}else{var l=readSym(e);return"."==l?null:(r="symbol","nil"==l||"t"==l||":"==l.charAt(0))?"atom":"open"==t.lastType&&(o.test(l)||a.test(l))?"keyword":"&"==l.charAt(0)?"variableName.special":"variableName"}}function inString(e,t){for(var n,r=!1;n=e.next();){if('"'==n&&!r){t.tokenize=base;break}r=!r&&"\\"==n}return"string"}function inComment(e,t){for(var n,o;n=e.next();){if("#"==n&&"|"==o){t.tokenize=base;break}o=n}return r="ws","comment"}let c={name:"commonlisp",startState:function(){return{ctx:{prev:null,start:0,indentTo:0},lastType:null,tokenize:base}},token:function(e,t){e.sol()&&"number"!=typeof t.ctx.indentTo&&(t.ctx.indentTo=t.ctx.start+1),r=null;var n=t.tokenize(e,t);return"ws"!=r&&(null==t.ctx.indentTo?"symbol"==r&&a.test(e.current())?t.ctx.indentTo=t.ctx.start+e.indentUnit:t.ctx.indentTo="next":"next"==t.ctx.indentTo&&(t.ctx.indentTo=e.column()),t.lastType=r),"open"==r?t.ctx={prev:t.ctx,start:e.column(),indentTo:null}:"close"==r&&(t.ctx=t.ctx.prev||t.ctx),n},indent:function(e){var t=e.ctx.indentTo;return"number"==typeof t?t:e.ctx.start+1},languageData:{commentTokens:{line:";;",block:{open:"#|",close:"|#"}},closeBrackets:{brackets:["(","[","{",'"']}}}}}]);
|
1
static/web/_next/static/chunks/1483.cb14b23fbe608c06.js
vendored
Normal file
1
static/web/_next/static/chunks/1483.cb14b23fbe608c06.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1483],{86233:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"}}]},name:"exclamation-circle",theme:"filled"}},31483:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a,n=(a=r(75036))&&a.__esModule?a:{default:a};t.default=n,e.exports=n},75036:function(e,t,r){var a=r(64836),n=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var u=a(r(42122)),f=function(e,t){if(e&&e.__esModule)return e;if(null===e||"object"!=n(e)&&"function"!=typeof e)return{default:e};var r=c(void 0);if(r&&r.has(e))return r.get(e);var a={__proto__:null},u=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var f in e)if("default"!==f&&({}).hasOwnProperty.call(e,f)){var l=u?Object.getOwnPropertyDescriptor(e,f):null;l&&(l.get||l.set)?Object.defineProperty(a,f,l):a[f]=e[f]}return a.default=e,r&&r.set(e,a),a}(r(67294)),l=a(r(86233)),o=a(r(3908));function c(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(c=function(e){return e?r:t})(e)}var i=f.forwardRef(function(e,t){return f.createElement(o.default,(0,u.default)((0,u.default)({},e),{},{ref:t,icon:l.default}))});t.default=i}}]);
|
@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1529],{57283:function(e,n,a){"use strict";a.r(n),a.d(n,{NameChangeModal:function(){return NameChangeModal}});var o=a(85893),t=a(67294),r=a(4480),l=a(51024),s=a(65400),i=a(64749),d=a(97538),c=a(92380),u=a(73580),h=a(53019),m=a.n(h);let{Option:p}=i.default,UserColor=e=>{let{color:n}=e;return(0,o.jsx)("div",{style:{textAlign:"center",backgroundColor:"var(--theme-color-users-".concat(n,")"),width:"100%",height:"100%"}})},NameChangeModal=e=>{let{closeModal:n}=e,a=(0,r.sJ)(u.db),h=(0,r.sJ)(u.Gt),[g,C]=(0,t.useState)(null==a?void 0:a.displayName);if(!a)return null;let{displayName:f,displayColor:y}=a,saveEnabled=()=>{let e=void 0!==g?Array.from(g).length:0;return g!==f&&e>0&&e<=30&&(null==h?void 0:h.isConnected())},handleNameChange=()=>{if(!saveEnabled())return;let e={type:c.C.NAME_CHANGE,newName:g};h.send(e),n()},v=[...Array(8)].map((e,n)=>n),b=(0,o.jsx)(s.default,{type:"primary",id:"name-change-submit",onClick:handleNameChange,disabled:!saveEnabled(),children:"Change name"});return(0,o.jsxs)("div",{children:["Your chat display name is what people see when you send chat messages.",(0,o.jsx)(d.default,{onSubmitCapture:handleNameChange,className:m().form,children:(0,o.jsx)(l.default.Search,{enterButton:b,id:"name-change-field",value:g,onChange:e=>C(e.target.value),placeholder:"Your chat display name","aria-label":"Your chat display name",showCount:{formatter:e=>e.count>30?"Over limit":""},defaultValue:f,className:m().inputGroup})}),(0,o.jsx)(d.default.Item,{label:"Your Color",className:m().colorChange,children:(0,o.jsx)(i.default,{style:{width:120},onChange:e=>{let n={type:c.C.COLOR_CHANGE,newColor:Number(e)};h.send(n)},defaultValue:y.toString(),className:m().colorDropdown,children:v.map(e=>(0,o.jsx)(p,{title:e,children:(0,o.jsx)(UserColor,{color:e,"aria-label":e.toString()})},e.toString()))})}),'You can also authenticate an IndieAuth or Fediverse account via the "Authenticate" menu.']})}},53019:function(e){e.exports={inputGroup:"NameChangeModal_inputGroup__7489y",colorChange:"NameChangeModal_colorChange__AkRZE",colorDropdown:"NameChangeModal_colorDropdown__tJ7mn","ant-select-customize-input":"NameChangeModal_ant-select-customize-input__aRklC"}},64217:function(e,n,a){"use strict";a.d(n,{Z:function(){return pickAttrs}});var o=a(1413),t="".concat("accept acceptCharset accessKey action allowFullScreen allowTransparency\n alt async autoComplete autoFocus autoPlay capture cellPadding cellSpacing challenge\n charSet checked classID className colSpan cols content contentEditable contextMenu\n controls coords crossOrigin data dateTime default defer dir disabled download draggable\n encType form formAction formEncType formMethod formNoValidate formTarget frameBorder\n headers height hidden high href hrefLang htmlFor httpEquiv icon id inputMode integrity\n is keyParams keyType kind label lang list loop low manifest marginHeight marginWidth max maxLength media\n mediaGroup method min minLength multiple muted name noValidate nonce open\n optimum pattern placeholder poster preload radioGroup readOnly rel required\n reversed role rowSpan rows sandbox scope scoped scrolling seamless selected\n shape size sizes span spellCheck src srcDoc srcLang srcSet start step style\n summary tabIndex target title type useMap value width wmode wrap"," ").concat("onCopy onCut onPaste onCompositionEnd onCompositionStart onCompositionUpdate onKeyDown\n onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit onClick onContextMenu onDoubleClick\n onDrag onDragEnd onDragEnter onDragExit onDragLeave onDragOver onDragStart onDrop onMouseDown\n onMouseEnter onMouseLeave onMouseMove onMouseOut onMouseOver onMouseUp onSelect onTouchCancel\n onTouchEnd onTouchMove onTouchStart onScroll onWheel onAbort onCanPlay onCanPlayThrough\n onDurationChange onEmptied onEncrypted onEnded onError onLoadedData onLoadedMetadata\n onLoadStart onPause onPlay onPlaying onProgress onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting onLoad onError").split(/[\s\n]+/);function match(e,n){return 0===e.indexOf(n)}function pickAttrs(e){var n,a=arguments.length>1&&void 0!==arguments[1]&&arguments[1];n=!1===a?{aria:!0,data:!0,attr:!0}:!0===a?{aria:!0}:(0,o.Z)({},a);var r={};return Object.keys(e).forEach(function(a){(n.aria&&("role"===a||match(a,"aria-"))||n.data&&match(a,"data-")||n.attr&&t.includes(a))&&(r[a]=e[a])}),r}}}]);
|
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1538],{79449:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 708c-22.1 0-40-17.9-40-40s17.9-40 40-40 40 17.9 40 40-17.9 40-40 40zm62.9-219.5a48.3 48.3 0 00-30.9 44.8V620c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8v-21.5c0-23.1 6.7-45.9 19.9-64.9 12.9-18.6 30.9-32.8 52.1-40.9 34-13.1 56-41.6 56-72.7 0-44.1-43.1-80-96-80s-96 35.9-96 80v7.6c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V420c0-39.3 17.2-76 48.4-103.3C430.4 290.4 470 276 512 276s81.6 14.5 111.6 40.7C654.8 344 672 380.7 672 420c0 57.8-38.1 109.8-97.1 132.5z"}}]},name:"question-circle",theme:"filled"}},11538:function(e,t,r){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var i=_interopRequireDefault(r(60259));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}t.default=i,e.exports=i},60259:function(e,t,r){var i=r(64836),u=r(18698);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=i(r(42122)),n=_interopRequireWildcard(r(67294)),l=i(r(79449)),c=i(r(92074));function _getRequireWildcardCache(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,r=new WeakMap;return(_getRequireWildcardCache=function(e){return e?r:t})(e)}function _interopRequireWildcard(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==u(e)&&"function"!=typeof e)return{default:e};var r=_getRequireWildcardCache(t);if(r&&r.has(e))return r.get(e);var i={},a=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var n in e)if("default"!==n&&Object.prototype.hasOwnProperty.call(e,n)){var l=a?Object.getOwnPropertyDescriptor(e,n):null;l&&(l.get||l.set)?Object.defineProperty(i,n,l):i[n]=e[n]}return i.default=e,r&&r.set(e,i),i}var QuestionCircleFilled=function(e,t){return n.createElement(c.default,(0,a.default)((0,a.default)({},e),{},{ref:t,icon:l.default}))};QuestionCircleFilled.displayName="QuestionCircleFilled";var o=n.forwardRef(QuestionCircleFilled);t.default=o}}]);
|
File diff suppressed because one or more lines are too long
1
static/web/_next/static/chunks/1639.a69f56d8e2858f44.js
vendored
Normal file
1
static/web/_next/static/chunks/1639.a69f56d8e2858f44.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/1650.06a77268379b94b2.js
vendored
Normal file
1
static/web/_next/static/chunks/1650.06a77268379b94b2.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/1660.76cc05d00e5034ad.js
vendored
Normal file
1
static/web/_next/static/chunks/1660.76cc05d00e5034ad.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1660],{11660: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,{d:function(){return w}});var i,o="body catch class do else enum for foreach foreach_reverse if in interface mixin out scope struct switch try union unittest version while with";let a={keywords:r("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue debug default delegate delete deprecated export extern final finally function goto immutable import inout invariant is lazy macro module new nothrow override package pragma private protected public pure ref return shared short static super synchronized template this throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters "+o),blockKeywords:r(o),builtin:r("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte ucent uint ulong ushort wchar wstring void size_t sizediff_t"),atoms:r("exit failure success true false null"),hooks:{"@":function(e,t){return e.eatWhile(/[\w\$_]/),"meta"}}};var u=a.statementIndentUnit,l=a.keywords,s=a.builtin,c=a.blockKeywords,f=a.atoms,d=a.hooks,p=a.multiLineStrings,m=/[+\-*&%=<>!?|\/]/;function h(e,t){var n=e.next();if(d[n]){var r=d[n](e,t);if(!1!==r)return r}if('"'==n||"'"==n||"`"==n)return t.tokenize=function(e,t){for(var r,i=!1,o=!1;null!=(r=e.next());){if(r==n&&!i){o=!0;break}i=!i&&"\\"==r}return(o||!(i||p))&&(t.tokenize=null),"string"},t.tokenize(e,t);if(/[\[\]{}\(\),;\:\.]/.test(n))return i=n,null;if(/\d/.test(n))return e.eatWhile(/[\w\.]/),"number";if("/"==n){if(e.eat("+"))return t.tokenize=k,k(e,t);if(e.eat("*"))return t.tokenize=y,y(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(m.test(n))return e.eatWhile(m),"operator";e.eatWhile(/[\w\$_\xa1-\uffff]/);var o=e.current();return l.propertyIsEnumerable(o)?(c.propertyIsEnumerable(o)&&(i="newstatement"),"keyword"):s.propertyIsEnumerable(o)?(c.propertyIsEnumerable(o)&&(i="newstatement"),"builtin"):f.propertyIsEnumerable(o)?"atom":"variable"}function y(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="*"==n}return"comment"}function k(e,t){for(var n,r=!1;n=e.next();){if("/"==n&&r){t.tokenize=null;break}r="+"==n}return"comment"}function b(e,t,n,r,i){this.indented=e,this.column=t,this.type=n,this.align=r,this.prev=i}function v(e,t,n){var r=e.indented;return e.context&&"statement"==e.context.type&&(r=e.context.indented),e.context=new b(r,t,n,null,e.context)}function _(e){var t=e.context.type;return(")"==t||"]"==t||"}"==t)&&(e.indented=e.context.indented),e.context=e.context.prev}let w={name:"d",startState:function(e){return{tokenize:null,context:new b(-e,0,"top",!1),indented:0,startOfLine:!0}},token:function(e,t){var n=t.context;if(e.sol()&&(null==n.align&&(n.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return null;i=null;var r=(t.tokenize||h)(e,t);if("comment"==r||"meta"==r)return r;if(null==n.align&&(n.align=!0),(";"==i||":"==i||","==i)&&"statement"==n.type)_(t);else if("{"==i)v(t,e.column(),"}");else if("["==i)v(t,e.column(),"]");else if("("==i)v(t,e.column(),")");else if("}"==i){for(;"statement"==n.type;)n=_(t);for("}"==n.type&&(n=_(t));"statement"==n.type;)n=_(t)}else i==n.type?_(t):(("}"==n.type||"top"==n.type)&&";"!=i||"statement"==n.type&&"newstatement"==i)&&v(t,e.column(),"statement");return t.startOfLine=!1,r},indent:function(e,t,n){if(e.tokenize!=h&&null!=e.tokenize)return null;var r=e.context,i=t&&t.charAt(0);"statement"==r.type&&"}"==i&&(r=r.prev);var o=i==r.type;return"statement"==r.type?r.indented+("{"==i?0:u||n.unit):r.align?r.column+(o?0:1):r.indented+(o?0:n.unit)},languageData:{indentOnInput:/^\s*[{}]$/,commentTokens:{line:"//",block:{open:"/*",close:"*/"}}}}}}]);
|
@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[1660],{11660:function(e,t,n){function words(e){for(var t={},n=e.split(" "),o=0;o<n.length;++o)t[n[o]]=!0;return t}n.r(t),n.d(t,{d:function(){return d}});var o,r="body catch class do else enum for foreach foreach_reverse if in interface mixin out scope struct switch try union unittest version while with";let i={keywords:words("abstract alias align asm assert auto break case cast cdouble cent cfloat const continue debug default delegate delete deprecated export extern final finally function goto immutable import inout invariant is lazy macro module new nothrow override package pragma private protected public pure ref return shared short static super synchronized template this throw typedef typeid typeof volatile __FILE__ __LINE__ __gshared __traits __vector __parameters "+r),blockKeywords:words(r),builtin:words("bool byte char creal dchar double float idouble ifloat int ireal long real short ubyte ucent uint ulong ushort wchar wstring void size_t sizediff_t"),atoms:words("exit failure success true false null"),hooks:{"@":function(e,t){return e.eatWhile(/[\w\$_]/),"meta"}}};var a=i.statementIndentUnit,u=i.keywords,s=i.builtin,l=i.blockKeywords,c=i.atoms,p=i.hooks,f=i.multiLineStrings,m=/[+\-*&%=<>!?|\/]/;function tokenBase(e,t){var n=e.next();if(p[n]){var r=p[n](e,t);if(!1!==r)return r}if('"'==n||"'"==n||"`"==n)return t.tokenize=tokenString(n),t.tokenize(e,t);if(/[\[\]{}\(\),;\:\.]/.test(n))return o=n,null;if(/\d/.test(n))return e.eatWhile(/[\w\.]/),"number";if("/"==n){if(e.eat("+"))return t.tokenize=tokenNestedComment,tokenNestedComment(e,t);if(e.eat("*"))return t.tokenize=tokenComment,tokenComment(e,t);if(e.eat("/"))return e.skipToEnd(),"comment"}if(m.test(n))return e.eatWhile(m),"operator";e.eatWhile(/[\w\$_\xa1-\uffff]/);var i=e.current();return u.propertyIsEnumerable(i)?(l.propertyIsEnumerable(i)&&(o="newstatement"),"keyword"):s.propertyIsEnumerable(i)?(l.propertyIsEnumerable(i)&&(o="newstatement"),"builtin"):c.propertyIsEnumerable(i)?"atom":"variable"}function tokenString(e){return function(t,n){for(var o,r=!1,i=!1;null!=(o=t.next());){if(o==e&&!r){i=!0;break}r=!r&&"\\"==o}return(i||!(r||f))&&(n.tokenize=null),"string"}}function tokenComment(e,t){for(var n,o=!1;n=e.next();){if("/"==n&&o){t.tokenize=null;break}o="*"==n}return"comment"}function tokenNestedComment(e,t){for(var n,o=!1;n=e.next();){if("/"==n&&o){t.tokenize=null;break}o="+"==n}return"comment"}function Context(e,t,n,o,r){this.indented=e,this.column=t,this.type=n,this.align=o,this.prev=r}function pushContext(e,t,n){var o=e.indented;return e.context&&"statement"==e.context.type&&(o=e.context.indented),e.context=new Context(o,t,n,null,e.context)}function popContext(e){var t=e.context.type;return(")"==t||"]"==t||"}"==t)&&(e.indented=e.context.indented),e.context=e.context.prev}let d={name:"d",startState:function(e){return{tokenize:null,context:new Context(-e,0,"top",!1),indented:0,startOfLine:!0}},token:function(e,t){var n=t.context;if(e.sol()&&(null==n.align&&(n.align=!1),t.indented=e.indentation(),t.startOfLine=!0),e.eatSpace())return null;o=null;var r=(t.tokenize||tokenBase)(e,t);if("comment"==r||"meta"==r)return r;if(null==n.align&&(n.align=!0),(";"==o||":"==o||","==o)&&"statement"==n.type)popContext(t);else if("{"==o)pushContext(t,e.column(),"}");else if("["==o)pushContext(t,e.column(),"]");else if("("==o)pushContext(t,e.column(),")");else if("}"==o){for(;"statement"==n.type;)n=popContext(t);for("}"==n.type&&(n=popContext(t));"statement"==n.type;)n=popContext(t)}else o==n.type?popContext(t):(("}"==n.type||"top"==n.type)&&";"!=o||"statement"==n.type&&"newstatement"==o)&&pushContext(t,e.column(),"statement");return t.startOfLine=!1,r},indent:function(e,t,n){if(e.tokenize!=tokenBase&&null!=e.tokenize)return null;var o=e.context,r=t&&t.charAt(0);"statement"==o.type&&"}"==r&&(o=o.prev);var i=r==o.type;return"statement"==o.type?o.indented+("{"==r?0:a||n.unit):o.align?o.column+(i?0:1):o.indented+(i?0:n.unit)},languageData:{indentOnInput:/^\s*[{}]$/,commentTokens:{line:"//",block:{open:"/*",close:"*/"}}}}}}]);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user