Compare commits
68 Commits
Author | SHA1 | Date |
---|---|---|
|
b871ccdd7c | |
|
59fa1bd369 | |
|
d814432ebb | |
|
247cc211fa | |
|
681225c2ae | |
|
47caf17973 | |
|
36de48cc94 | |
|
63556e2983 | |
|
9dff066a9c | |
|
f6d1ecd757 | |
|
aa0f47607f | |
|
77c42dffd8 | |
|
9bba5db233 | |
|
c2b70e2ead | |
|
e59915a8f5 | |
|
74ea23add9 | |
|
06ba575c42 | |
|
8e4a9cb4f1 | |
|
dd84590ac7 | |
|
8f9119d566 | |
|
efb5aa8a33 | |
|
2a51b37e81 | |
|
7cecc16695 | |
|
74ea74f691 | |
|
66072d125b | |
|
c829fa8a37 | |
|
94b2851984 | |
|
b535db6108 | |
|
a6ae38e1df | |
|
13c2054eaa | |
|
a68fcaf976 | |
|
9c98c333ad | |
|
ffb35c3220 | |
|
75b5c4160d | |
|
c4d9feb02a | |
|
a9e2006247 | |
|
8e6a2b40db | |
|
f0bf42dcbe | |
|
b12ee11179 | |
|
5eae3f7f18 | |
|
48addc37b4 | |
|
52d68149a7 | |
|
2bc13453f4 | |
|
8d2662d0dc | |
|
496f246a2d | |
|
1a4f6ebaf2 | |
|
b428fb2de2 | |
|
3704bb2231 | |
|
d7e5ccc332 | |
|
cbe05cc788 | |
|
3030588ffd | |
|
ad39db4aac | |
|
58f3c2f36e | |
|
82d396d3c9 | |
|
d94bb110a6 | |
|
70223a8040 | |
|
81120bf333 | |
|
5598b6bedf | |
|
2b771aa6b8 | |
|
f8bd23690b | |
|
08251502f5 | |
|
96bffc8fb0 | |
|
3b9d08ebbd | |
|
c80ebfafa3 | |
|
e23014c444 | |
|
ceb764934f | |
|
878339ad18 | |
|
08a6ab0da7 |
|
@ -3,9 +3,9 @@ testdata_dir = "testdata"
|
|||
tmp_dir = "tmp"
|
||||
|
||||
[build]
|
||||
args_bin = ["-l", "0.0.0.0"]
|
||||
args_bin = ["-l", "0.0.0.0", "-p", "3000"]
|
||||
bin = "./out/ytdl-web"
|
||||
cmd = "task build"
|
||||
cmd = "build"
|
||||
delay = 1000
|
||||
exclude_dir = [
|
||||
"assets",
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
if ! has nix_direnv_version || ! nix_direnv_version 2.2.1; then
|
||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.1/direnvrc" "sha256-zelF0vLbEl5uaqrfIzbgNzJWGmLzCmYAkInj/LNxvKs="
|
||||
fi
|
||||
|
||||
nix_direnv_watch_file nix/devenv.nix
|
||||
nix_direnv_watch_file devenv.lock
|
||||
nix_direnv_watch_file devenv.yaml
|
||||
if ! use flake . --impure
|
||||
then
|
||||
echo "devenv could not be built. The devenv environment was not loaded. Make the necessary changes to devenv.nix and hit enter to try again." >&2
|
||||
fi
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
name: Release
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
goreleaser:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- uses: https://github.com/goreleaser/goreleaser-action@v2
|
||||
with:
|
||||
version: latest
|
||||
args: release --clean
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: https://github.com/docker/metadata-action@v4
|
||||
with:
|
||||
# list of Docker images to use as base name for tags
|
||||
images: git.fifitido.net/apps/ytdl-web
|
||||
# generate Docker tags based on the following events/attributes
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=sha
|
||||
- name: Setup QEMU
|
||||
uses: https://github.com/docker/setup-qemu-action@v2
|
||||
- name: Setup Docker Buildx
|
||||
uses: https://github.com/docker/setup-buildx-action@v2
|
||||
- name: Login to Docker Registry
|
||||
uses: https://github.com/docker/login-action@v2
|
||||
with:
|
||||
registry: git.fifitido.net
|
||||
username: ${{ gitea.repository_owner }}
|
||||
password: ${{ secrets.GITEA_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: https://github.com/docker/build-push-action@v4
|
||||
with:
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# yamllint disable rule:line-length
|
||||
build-args: |
|
||||
VERSION=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.version'] }}
|
||||
BUILD=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.revision'] }}
|
||||
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
|
||||
BUILT_BY=Gitea Actions
|
||||
# yamllint enable rule:line-length
|
|
@ -0,0 +1,24 @@
|
|||
---
|
||||
name: "Test"
|
||||
|
||||
# yamllint disable-line rule:truthy
|
||||
on:
|
||||
{}
|
||||
# pull_request:
|
||||
# push:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: https://github.com/cachix/install-nix-action@v18
|
||||
# - uses: https://github.com/cachix/cachix-action@v12
|
||||
# with:
|
||||
# name: ytdl-web
|
||||
# extraPullNames: devenv
|
||||
# authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
- name: Install devenv.sh
|
||||
run: nix profile install github:cachix/devenv/latest
|
||||
- run: devenv shell echo ok
|
||||
- run: devenv ci
|
|
@ -4,3 +4,13 @@
|
|||
dist/
|
||||
config.yaml
|
||||
cookies.txt
|
||||
|
||||
# Devenv
|
||||
.devenv*
|
||||
devenv.local.nix
|
||||
|
||||
# direnv
|
||||
.direnv
|
||||
|
||||
# pre-commit
|
||||
.pre-commit-config.yaml
|
|
@ -1,6 +1,8 @@
|
|||
---
|
||||
project_name: ytdl-web
|
||||
env:
|
||||
- BASE_PKG=go.fifitido.net/ytdl-web
|
||||
force_token: gitea
|
||||
gitea_urls:
|
||||
api: https://git.fifitido.net/api/v1
|
||||
download: https://git.fifitido.net
|
||||
|
@ -35,57 +37,10 @@ builds:
|
|||
- -X {{ .Env.BASE_PKG }}/version.Build={{.ShortCommit}}
|
||||
- -X {{ .Env.BASE_PKG }}/version.BuildDate={{.Date}}
|
||||
- -X {{ .Env.BASE_PKG }}/version.BuiltBy=goreleaser
|
||||
dockers:
|
||||
- image_templates:
|
||||
- &amd64_image git.fifitido.net/apps/{{.ProjectName}}:{{.Tag}}-amd64
|
||||
use: buildx
|
||||
dockerfile: Dockerfile
|
||||
goos: linux
|
||||
goarch: amd64
|
||||
build_flag_templates:
|
||||
- --platform=linux/amd64
|
||||
- image_templates:
|
||||
- &arm64v8_image git.fifitido.net/apps/{{.ProjectName}}:{{.Tag}}-arm64v8
|
||||
use: buildx
|
||||
dockerfile: Dockerfile
|
||||
goos: linux
|
||||
goarch: arm64
|
||||
build_flag_templates:
|
||||
- --platform=linux/arm64/v8
|
||||
- image_templates:
|
||||
- &armv7_image git.fifitido.net/apps/{{.ProjectName}}:{{.Tag}}-armv7
|
||||
use: buildx
|
||||
dockerfile: Dockerfile
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 7
|
||||
build_flag_templates:
|
||||
- --platform=linux/arm/v7
|
||||
- image_templates:
|
||||
- &armv6_image git.fifitido.net/apps/{{.ProjectName}}:{{.Tag}}-armv6
|
||||
use: buildx
|
||||
dockerfile: Dockerfile
|
||||
goos: linux
|
||||
goarch: arm
|
||||
goarm: 6
|
||||
build_flag_templates:
|
||||
- --platform=linux/arm/v6
|
||||
docker_manifests:
|
||||
- name_template: git.fifitido.net/apps/{{.ProjectName}}:latest
|
||||
image_templates:
|
||||
- *amd64_image
|
||||
- *arm64v8_image
|
||||
- *armv7_image
|
||||
- *armv6_image
|
||||
- name_template: git.fifitido.net/apps/{{.ProjectName}}:{{.Tag}}
|
||||
image_templates:
|
||||
- *amd64_image
|
||||
- *arm64v8_image
|
||||
- *armv7_image
|
||||
- *armv6_image
|
||||
archives:
|
||||
- format: tar.gz
|
||||
# this name template makes the OS and Arch compatible with the results of uname.
|
||||
# this name template makes the OS and Arch
|
||||
# compatible with the results of uname.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
*out
|
||||
*logs
|
||||
*actions
|
||||
*notifications
|
||||
plugins
|
||||
user_trunk.yaml
|
||||
user.yaml
|
|
@ -1,4 +0,0 @@
|
|||
# Following source doesn't work in most setups
|
||||
ignored:
|
||||
- SC1090
|
||||
- SC1091
|
|
@ -1,10 +0,0 @@
|
|||
rules:
|
||||
quoted-strings:
|
||||
required: only-when-needed
|
||||
extra-allowed: ["{|}"]
|
||||
empty-values:
|
||||
forbid-in-block-mappings: true
|
||||
forbid-in-flow-mappings: true
|
||||
key-duplicates: {}
|
||||
octal-values:
|
||||
forbid-implicit-octal: true
|
|
@ -1,28 +0,0 @@
|
|||
version: 0.1
|
||||
cli:
|
||||
version: 1.7.0
|
||||
plugins:
|
||||
sources:
|
||||
- id: trunk
|
||||
ref: v0.0.15
|
||||
uri: https://github.com/trunk-io/plugins
|
||||
lint:
|
||||
enabled:
|
||||
- git-diff-check
|
||||
- gitleaks@8.16.2
|
||||
- gofmt@1.19.3
|
||||
- golangci-lint@1.52.2
|
||||
- hadolint@2.12.0
|
||||
- prettier@2.8.7
|
||||
- taplo@0.7.0
|
||||
- yamllint@1.30.0
|
||||
ignore:
|
||||
- linters:
|
||||
- yamllint
|
||||
paths:
|
||||
- charts
|
||||
runtimes:
|
||||
enabled:
|
||||
- go@1.19.5
|
||||
- node@18.12.1
|
||||
- python@3.10.8
|
45
Dockerfile
45
Dockerfile
|
@ -1,19 +1,50 @@
|
|||
ARG ALPINE_VERSION="3.17"
|
||||
ARG GOLANG_VERSION="1.22.1"
|
||||
ARG DEBIAN_VERSION="bookworm"
|
||||
|
||||
FROM alpine:${ALPINE_VERSION}
|
||||
FROM golang:${GOLANG_VERSION}-${DEBIAN_VERSION} AS build
|
||||
|
||||
ENV VERSION_PKG="go.fifitido.net/ytdl-web/version"
|
||||
ARG VERSION=latest
|
||||
ARG BUILD="unknown"
|
||||
ARG BUILD_DATE="unknown"
|
||||
ARG BUILT_BY="docker"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG YTDLP_VERSION="2023.03.04-r0"
|
||||
ARG FFMPEG_VERSION="5.1.3-r0"
|
||||
RUN apk add --no-cache yt-dlp==${YTDLP_VERSION} ffmpeg==${FFMPEG_VERSION}
|
||||
COPY go.mod go.sum ./
|
||||
|
||||
COPY ytdl-web ./
|
||||
RUN go mod download
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go build \
|
||||
-ldflags=" \
|
||||
-X $VERSION_PKG.Version=$VERSION \
|
||||
-X $VERSION_PKG.Build=$BUILD \
|
||||
-X $VERSION_PKG.BuildDate=$BUILD_DATE \
|
||||
-X \"$VERSION_PKG.BuiltBy=$BUILT_BY\" \
|
||||
" -o /ytdl-web .
|
||||
|
||||
FROM python:${DEBIAN_VERSION}
|
||||
|
||||
ARG YTDLP_VERSION="2024.11.04"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# hadolint ignore=DL3008
|
||||
RUN apt-get update \
|
||||
&& apt-get install --no-install-recommends -y wget \
|
||||
&& wget --progress=dot:giga "https://github.com/yt-dlp/yt-dlp/releases/download/${YTDLP_VERSION}/yt-dlp" \
|
||||
&& install -pm755 yt-dlp /usr/bin/yt-dlp \
|
||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY --from=build /ytdl-web ./
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENV YTDL_HTTP_PORT=8080 \
|
||||
YTDL_HTTP_LISTEN=0.0.0.0 \
|
||||
YTDL_BINARYPATH=/usr/bin/yt-dlp
|
||||
YTDL_BINARYPATH=/usr/bin/yt-dlp \
|
||||
YTDL_CONFIGDIR=/config
|
||||
|
||||
ENTRYPOINT [ "./ytdl-web" ]
|
62
README.md
62
README.md
|
@ -15,65 +15,69 @@ Available options:
|
|||
- -p, --port int port to listen on (default 8080)
|
||||
- -y, --ytdlp-path string the path to the yt-dlp binary, used when it is not in $PATH (default "yt-dlp")
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment variables
|
||||
|
||||
You can configure the application using environment variables
|
||||
|
||||
| Variable Name | Description | Default Value | Accepted Values |
|
||||
| ---------------------------------- | ----------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------ |
|
||||
| YTDL_CONFIGDIR | Add a custom config directory to search for the config file | ` ` | |
|
||||
| YTDL_ENV | The application environment | `Production` | `Development`, `Staging`, `Production` |
|
||||
| YTDL_YTDLP_BINARYPATH | The path to the yt-dlp binary | `yt-dlp` | |
|
||||
| YTDL_HTTP_PORT | The tcp port for the web server to listen on | `8080` | |
|
||||
| YTDL_HTTP_LISTEN | The address for the web server to listen on | `127.0.0.1` | `0.0.0.0`, `127.0.0.1`, etc. |
|
||||
| YTDL_HTTP_BASEPATH | The base path of the application, useful for reverse proxies | `/` | |
|
||||
| YTDL_CACHE_TTL | How long to keep cached metadata | `1h` | `1h`, `30s`, `2m`, etc. |
|
||||
| YTDL_CACHE_DIRPATH | The path to the directory of where to store the cache | `/tmp/ytdl-web` | |
|
||||
| YTDL_COOKIES_ENABLED | Whether to use cookies when using yt-dlp | `true` | `true` or `false` |
|
||||
| YTDL_COOKIES_FILEPATH | The path to the netscape format cookies file | `./cookies.txt` | |
|
||||
| YTDL_COOKIES_FROMBROWSER_BROWSER | The name of the browser to load cookies from. (if specified, it disables YTDL_COOKIES_FILEPATH) | ` ` | `brave`, `chrome`, `chromium`, `edge`, `firefox`, `opera`, `safari`, `vivaldi` |
|
||||
| YTDL_COOKIES_FROMBROWSER_KEYRING | The name of the keyring for decrypting cookies for the chromium browser on linux | ` ` | `basictext`, `gnomekeyring`, `kwallet` |
|
||||
| YTDL_COOKIES_FROMBROWSER_PROFILE | The browser profile to load cookies from | ` ` | |
|
||||
| YTDL_COOKIES_FROMBROWSER_CONTAINER | The container name (if firefox) to load the cookies from | ` ` | |
|
||||
|
||||
## Building from source
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- [go v1.20](https://go.dev/doc/install)
|
||||
- [task cli](https://taskfile.dev/installation/)
|
||||
- [devenv](https://devenv.sh/getting-started/)
|
||||
|
||||
Steps:
|
||||
|
||||
1. Download dependencies
|
||||
1. Enter devenv shell
|
||||
|
||||
```sh
|
||||
task deps
|
||||
devenv shell
|
||||
```
|
||||
|
||||
2. Build binary
|
||||
2. Run the build script
|
||||
|
||||
```sh
|
||||
task build
|
||||
build
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- [go v1.20](https://go.dev/doc/install)
|
||||
- [goreleaser](https://goreleaser.com/install/)
|
||||
- [task cli](https://taskfile.dev/installation/)
|
||||
- [devenv](https://devenv.sh/getting-started/)
|
||||
|
||||
Steps:
|
||||
|
||||
1. Ensure gitea access token is in `~/.config/goreleaser/gitea_token`
|
||||
|
||||
2. Run release task
|
||||
2. Enter devenv shell
|
||||
|
||||
```sh
|
||||
task release
|
||||
devenv shell
|
||||
```
|
||||
|
||||
## Publishing Chart
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- [helm cli](https://helm.sh/docs/intro/install/)
|
||||
- [cm-push helm plugin](https://github.com/chartmuseum/helm-push/).
|
||||
- [task cli](https://taskfile.dev/installation/)
|
||||
|
||||
Steps:
|
||||
|
||||
1. Add the helm repo
|
||||
3. Run the release script
|
||||
|
||||
```sh
|
||||
helm repo add --username {username} --password {password} gitea-apps https://git.fifitido.net/api/packages/apps/helm
|
||||
```
|
||||
|
||||
2. Publish the chart
|
||||
|
||||
```sh
|
||||
task publish-chart
|
||||
release
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
|
41
Taskfile.yml
41
Taskfile.yml
|
@ -1,41 +0,0 @@
|
|||
version: "3"
|
||||
|
||||
vars:
|
||||
OUT: ./out/ytdl-web
|
||||
VERSION: 1.0.3
|
||||
VERSION_PKG: go.fifitido.net/ytdl-web/version
|
||||
BUILD:
|
||||
sh: git rev-parse --short HEAD
|
||||
DATE:
|
||||
sh: date -Iseconds
|
||||
DOCKER_IMAGE: git.fifitido.net/apps/ytdl-web
|
||||
DOCKER_IMAGE_TAG: latest
|
||||
|
||||
tasks:
|
||||
deps: go mod download
|
||||
tidy: go mod tidy
|
||||
check: goreleaser check
|
||||
build: >
|
||||
go build -ldflags="
|
||||
-X {{.VERSION_PKG}}.Version={{.VERSION}}
|
||||
-X {{.VERSION_PKG}}.Build={{.BUILD}}
|
||||
-X {{.VERSION_PKG}}.BuildDate={{.DATE}}
|
||||
-X {{.VERSION_PKG}}.BuiltBy=taskfile
|
||||
"
|
||||
-o {{.OUT}} .
|
||||
dev: air
|
||||
clean:
|
||||
cmds:
|
||||
- rm -rf ./dist/ ./out/ ./tmp/
|
||||
- go clean
|
||||
release:
|
||||
deps:
|
||||
- clean
|
||||
cmds:
|
||||
- goreleaser release
|
||||
chart:deps:
|
||||
cmds:
|
||||
- helm repo add bjw-s https://bjw-s.github.io/helm-charts
|
||||
- helm dependency build
|
||||
dir: charts/ytdl-web
|
||||
chart:publish: helm cm-push charts/ytdl-web/ gitea-apps
|
|
@ -0,0 +1,180 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/spf13/viper"
|
||||
"go.fifitido.net/ytdl-web/app"
|
||||
"go.fifitido.net/ytdl-web/app/models"
|
||||
"go.fifitido.net/ytdl-web/pkg/htmx"
|
||||
"go.fifitido.net/ytdl-web/pkg/httpx"
|
||||
"go.fifitido.net/ytdl-web/pkg/server"
|
||||
"go.fifitido.net/ytdl-web/pkg/view"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||
"go.fifitido.net/ytdl-web/version"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type DownloadController struct {
|
||||
ytdl ytdl.Ytdl
|
||||
}
|
||||
|
||||
var _ server.Controller = (*DownloadController)(nil)
|
||||
|
||||
func NewDownloadController(ytdl ytdl.Ytdl) *DownloadController {
|
||||
return &DownloadController{
|
||||
ytdl: ytdl,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *DownloadController) Router(r chi.Router) {
|
||||
r.Get("/", c.ListDownloadLinks)
|
||||
r.Head("/proxy", c.ProxyDownload)
|
||||
r.Get("/proxy", c.ProxyDownload)
|
||||
}
|
||||
|
||||
func (c *DownloadController) getUrlParam(r *http.Request) (string, bool) {
|
||||
urlRaw, err := httpx.Query(r, "url")
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
|
||||
urlBytes, err := url.QueryUnescape(urlRaw)
|
||||
if err != nil || len(urlBytes) < 1 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return urlBytes, true
|
||||
}
|
||||
|
||||
func (c *DownloadController) ListDownloadLinks(w http.ResponseWriter, r *http.Request) {
|
||||
hx := htmx.New(w, r)
|
||||
var layout []string
|
||||
if !hx.IsHtmxRequest() {
|
||||
layout = append(layout, "layouts/main")
|
||||
}
|
||||
|
||||
isSecure := r.URL.Scheme == "https" || r.Header.Get("X-Forwarded-Proto") == "https"
|
||||
|
||||
videoUrl, ok := c.getUrlParam(r)
|
||||
if !ok {
|
||||
app.Views.Render(w, "index", view.Data{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"BinaryVersion": c.ytdl.Version(),
|
||||
"IsSecure": isSecure,
|
||||
"Error": view.Data{
|
||||
"Message": "Invalid URL",
|
||||
},
|
||||
}, layout...)
|
||||
return
|
||||
}
|
||||
|
||||
meta, err := c.ytdl.GetMetadata(videoUrl)
|
||||
if err != nil {
|
||||
app.Views.Render(w, "index", view.Data{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"BinaryVersion": c.ytdl.Version(),
|
||||
"IsSecure": isSecure,
|
||||
"Error": view.Data{
|
||||
"Message": "Could not find a video at that url",
|
||||
"RetryUrl": videoUrl,
|
||||
},
|
||||
}, layout...)
|
||||
return
|
||||
}
|
||||
|
||||
if hx.IsHtmxRequest() {
|
||||
hx.PushUrl("/download?url=" + url.QueryEscape(videoUrl))
|
||||
}
|
||||
|
||||
app.Views.Render(w, "download", view.Data{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"BinaryVersion": c.ytdl.Version(),
|
||||
"IsSecure": isSecure,
|
||||
"Url": videoUrl,
|
||||
"Meta": meta,
|
||||
"Videos": models.GetVideosFromMetadata(meta),
|
||||
}, layout...)
|
||||
}
|
||||
|
||||
var (
|
||||
BUF_LEN = 1024
|
||||
)
|
||||
|
||||
func (c *DownloadController) ProxyDownload(w http.ResponseWriter, r *http.Request) {
|
||||
videoUrl, ok := c.getUrlParam(r)
|
||||
if !ok {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
formatId, err := httpx.Query(r, "format")
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
meta, err := c.ytdl.GetMetadata(videoUrl)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get metadata", slog.String("error", err.Error()))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
videos := models.GetVideosFromMetadata(meta)
|
||||
|
||||
index, err := httpx.QueryInt(r, "index")
|
||||
if err != nil || index < 0 || index >= len(videos) {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
video := videos[index]
|
||||
|
||||
var format *metadata.Format
|
||||
for _, f := range video.Formats {
|
||||
if f.FormatID == formatId {
|
||||
format = &f
|
||||
break
|
||||
}
|
||||
}
|
||||
if format == nil {
|
||||
http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext))
|
||||
if format.Filesize != nil {
|
||||
w.Header().Set("Content-Length", fmt.Sprint(*format.Filesize))
|
||||
}
|
||||
|
||||
if len(videos) == 1 {
|
||||
index = -1
|
||||
}
|
||||
|
||||
read, write := io.Pipe()
|
||||
|
||||
go func() {
|
||||
_, err := io.Copy(w, read)
|
||||
if err != nil {
|
||||
slog.Error("Failed to copy", slog.String("error", err.Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
if err := c.ytdl.Download(write, videoUrl, format.FormatID, index); err != nil {
|
||||
slog.Error("Failed to download", slog.String("error", err.Error()))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
write.Close()
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/spf13/viper"
|
||||
"go.fifitido.net/ytdl-web/app"
|
||||
"go.fifitido.net/ytdl-web/pkg/htmx"
|
||||
"go.fifitido.net/ytdl-web/pkg/server"
|
||||
"go.fifitido.net/ytdl-web/pkg/view"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||
"go.fifitido.net/ytdl-web/version"
|
||||
)
|
||||
|
||||
type HomeController struct {
|
||||
ytdl ytdl.Ytdl
|
||||
}
|
||||
|
||||
var _ server.Controller = (*HomeController)(nil)
|
||||
|
||||
func NewHomeController(ytdl ytdl.Ytdl) *HomeController {
|
||||
return &HomeController{
|
||||
ytdl: ytdl,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *HomeController) Router(r chi.Router) {
|
||||
r.Get("/", c.Index)
|
||||
}
|
||||
|
||||
func (c *HomeController) Index(w http.ResponseWriter, r *http.Request) {
|
||||
hx := htmx.New(w, r)
|
||||
isSecure := r.URL.Scheme == "https" || r.Header.Get("X-Forwarded-Proto") == "https"
|
||||
|
||||
if hx.IsHtmxRequest() {
|
||||
hx.PushUrl("/")
|
||||
|
||||
app.Views.Render(w, "index", view.Data{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"BinaryVersion": c.ytdl.Version(),
|
||||
"IsSecure": isSecure,
|
||||
})
|
||||
} else {
|
||||
app.Views.Render(w, "index", view.Data{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"BinaryVersion": c.ytdl.Version(),
|
||||
"IsSecure": isSecure,
|
||||
}, "layouts/main")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||
)
|
||||
|
||||
type Video struct {
|
||||
Meta *metadata.Metadata
|
||||
Formats []metadata.Format
|
||||
OtherFormats []metadata.Format
|
||||
}
|
||||
|
||||
func GetVideosFromMetadata(meta *metadata.Metadata) []Video {
|
||||
if meta.IsPlaylist() {
|
||||
videos := make([]Video, 0, len(meta.Entries))
|
||||
|
||||
for _, entry := range meta.Entries {
|
||||
videos = append(videos, GetVideosFromMetadata(&entry)...)
|
||||
}
|
||||
|
||||
return videos
|
||||
}
|
||||
|
||||
formats := []metadata.Format{}
|
||||
otherFormats := []metadata.Format{}
|
||||
|
||||
for _, format := range meta.Formats {
|
||||
if format.ACodec != "none" && format.VCodec != "none" && format.Protocol != "m3u8_native" {
|
||||
formats = append(formats, format)
|
||||
} else {
|
||||
otherFormats = append(otherFormats, format)
|
||||
}
|
||||
}
|
||||
|
||||
for i, j := 0, len(formats)-1; i < j; i, j = i+1, j-1 {
|
||||
formats[i], formats[j] = formats[j], formats[i]
|
||||
}
|
||||
|
||||
return []Video{
|
||||
{
|
||||
Meta: meta,
|
||||
Formats: formats,
|
||||
OtherFormats: otherFormats,
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"net/url"
|
||||
|
||||
"github.com/htfy96/reformism"
|
||||
"go.fifitido.net/ytdl-web/pkg/view/html"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||
)
|
||||
|
||||
//go:embed views/*
|
||||
var viewsfs embed.FS
|
||||
|
||||
var Views = html.New(
|
||||
viewsfs,
|
||||
html.DefaultOptions().
|
||||
WithBaseDir("views").
|
||||
WithFunction("unsafe", func(s string) template.HTML {
|
||||
return template.HTML(s)
|
||||
}).
|
||||
WithFunction("queryEscape", func(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
}).
|
||||
WithFunction("jsonMarshal", func(s any) (string, error) {
|
||||
j, err := json.MarshalIndent(s, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(j), nil
|
||||
}).
|
||||
WithFunction("downloadContext", func(meta metadata.Metadata, url, basePath string, format metadata.Format) map[string]any {
|
||||
return map[string]any{
|
||||
"Meta": meta,
|
||||
"Url": url,
|
||||
"BasePath": basePath,
|
||||
"Format": format,
|
||||
}
|
||||
}).
|
||||
WithFunction("sprintf", func(format string, args ...any) string {
|
||||
return fmt.Sprintf(format, args...)
|
||||
}).
|
||||
WithFunction("filesize", func(size *int) string {
|
||||
if size == nil {
|
||||
return "unknown"
|
||||
}
|
||||
const unit = 1000
|
||||
if *size < unit {
|
||||
return fmt.Sprintf("%d B", *size)
|
||||
}
|
||||
div, exp := int64(unit), 0
|
||||
for n := *size / unit; n >= unit; n /= unit {
|
||||
div *= unit
|
||||
exp++
|
||||
}
|
||||
return fmt.Sprintf("%.1f %cB",
|
||||
float64(*size)/float64(div), "kMGTPE"[exp])
|
||||
}).
|
||||
WithFunctions(reformism.FuncsHTML),
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := Views.Load(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<div class="d-flex flex-column align-items-center">
|
||||
<h1>Download Video</h1>
|
||||
<h2 class="fs-4 text-muted text-center">{{.Meta.Title}}</h2>
|
||||
<p style="font-size: 0.85rem">{{.Url}}</p>
|
||||
<a href="{{.BasePath}}/" hx-get="{{.BasePath}}/" hx-trigger="click" hx-target="#main-content"
|
||||
class="btn btn-secondary btn-sm mt-3" style="width: 30rem; max-width: 100%">
|
||||
Download Another Video
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{$root := .}}
|
||||
{{range $vidIndex, $video := .Videos}}
|
||||
{{if not (eq $vidIndex 0)}}
|
||||
<hr class="mt-5" />
|
||||
{{end}}
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-center gap-5 mt-5">
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="{{$video.Meta.Thumbnail}}" alt="{{$video.Meta.Title}}" style="max-height: 25rem; max-width: 100%; margin: 0 auto" />
|
||||
</div>
|
||||
<div class="downloads flex-lg-grow-1">
|
||||
{{range $index, $format := $video.Formats}}
|
||||
{{template "format" (map "root" $root "format" $format "label" $format.Format "vidIndex" $vidIndex)}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if gt (len $video.OtherFormats) 0}}
|
||||
<div class="d-grid my-3">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#collapse-{{$root.Meta.ID}}-{{$vidIndex}}"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapse-{{$root.Meta.ID}}-{{$vidIndex}}"
|
||||
>
|
||||
See More Formats
|
||||
</button>
|
||||
</div>
|
||||
<div id="collapse-{{$root.Meta.ID}}-{{$vidIndex}}" class="collapse">
|
||||
<div class="downloads d-flex d-md-grid flex-column">
|
||||
{{range $index, $format := $video.OtherFormats}}
|
||||
{{$label := sprintf "ext: %s, resolution: %s, filesize: %s, note: %s" $format.Ext $format.Resolution
|
||||
(filesize $format.Filesize) $format.FormatNote}}
|
||||
{{template "format" (map "root" $root "format" $format "label" $label "vidIndex" $vidIndex)}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{define "format"}}
|
||||
<div style="font-size: smaller">{{.label}}</div>
|
||||
<div class="flex-grow-1 d-flex gap-3">
|
||||
<a class="btn btn-primary flex-grow-1" download="{{.root.Meta.ID}}-{{.format.Resolution}}.{{.format.Ext}}" P
|
||||
href="{{.format.Url}}">
|
||||
Download (direct)
|
||||
</a>
|
||||
<a class="btn btn-primary flex-grow-1" download="{{.root.Meta.ID}}-{{.format.Resolution}}.{{.format.Ext}}"
|
||||
href="{{.root.BasePath}}/download/proxy?url={{queryEscape .root.Url}}&format={{.format.FormatID}}&index={{.vidIndex}}">
|
||||
Download (proxied)
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
|
@ -1,19 +1,20 @@
|
|||
<h1 class="text-center">YTDL Web</h1>
|
||||
<p class="text-center mb-5">
|
||||
Download videos from over a thousand websites with the help of
|
||||
<a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a>,
|
||||
a fork of youtube-dl with more features and fixes.
|
||||
<a href="https://github.com/yt-dlp/yt-dlp">yt-dlp</a>, a fork of youtube-dl
|
||||
with more features and fixes.
|
||||
<br />
|
||||
View a complete list of supported websites
|
||||
<a href="https://github.com/yt-dlp/yt-dlp/blob/master/supportedsites.md">here</a>.
|
||||
</p>
|
||||
|
||||
<form action="{{.BasePath}}/download" method="get">
|
||||
<form hx-get="{{.BasePath}}/download" hx-trigger="submit" hx-target="#main-content" hx-swap="innerHTML">
|
||||
<div class="mb-3">
|
||||
<label for="url" class="form-label visually-hidden">Url</label>
|
||||
<div class="input-group">
|
||||
<input type="url" name="url" id="url" class="form-control" required
|
||||
placeholder="Enter url here then click download" />
|
||||
{{if .IsSecure}}
|
||||
<button id="paste-button" class="btn btn-outline-secondary" type="button" title="Paste">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"
|
||||
style="width: 1.5rem; height: 1.5rem">
|
||||
|
@ -21,12 +22,31 @@
|
|||
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184" />
|
||||
</svg>
|
||||
</button>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-grid">
|
||||
<button type="submit" class="btn btn-primary">Download</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Download
|
||||
<div class="spinner-border spinner-border-sm htmx-indicator ms-1" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
{{if .Flash}}
|
||||
<div class="alert alert-danger mt-4" role="" alert>{{.Flash.message}}</div>
|
||||
{{end}}
|
||||
</form>
|
||||
|
||||
{{if .Error}}
|
||||
<div class="alert alert-danger mt-4" role="alert">
|
||||
<span>{{.Error.Message}}</span>
|
||||
|
||||
{{if .Error.RetryUrl}}
|
||||
<button class="btn btn-link btn-sm pt-0 lh-base text-decoration-none" hx-get="/download" hx-trigger="click"
|
||||
hx-target="#main-content" hx-swap="innerHTML" hx-vals='{"url": "{{.Error.RetryUrl}}"}'>
|
||||
<span class="text-decoration-underline">Try Again</span>
|
||||
<div class="spinner-border spinner-border-sm htmx-indicator ms-1" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</button>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en" class="h-100">
|
||||
|
||||
<head>
|
||||
|
@ -6,16 +6,18 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>YTDL Web</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous" />
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.css"
|
||||
integrity="sha256-R91pD48xW+oHbpJYGn5xR0Q7tMhH4xOrWn1QqMRINtA=" crossorigin="anonymous" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"
|
||||
defer></script>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/toastr@2.1.4/build/toastr.min.js"
|
||||
integrity="sha256-Hgwq1OBpJ276HUP9H3VJkSv9ZCGRGQN+JldPJ8pNcUM=" crossorigin="anonymous" defer></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/htmx.org@1.9.4/dist/htmx.min.js"
|
||||
integrity="sha256-XIivRAE99i/eil5P31JNihaDSiix0V40rgmUrCfNTH4=" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
#toast-container>div {
|
||||
-moz-box-shadow: none !important;
|
||||
|
@ -42,13 +44,19 @@
|
|||
|
||||
<body class="d-flex flex-column h-100" data-bs-theme="dark">
|
||||
<div class="flex-shrink-0">
|
||||
{{template "views/partials/navbar" .}}
|
||||
<main class="container my-5">{{embed}}</main>
|
||||
{{template "partials/navbar" .}}
|
||||
<main id="main-content" class="container my-5">{{yield}}</main>
|
||||
</div>
|
||||
{{template "views/partials/footer" .}}
|
||||
{{template "partials/footer" .}}
|
||||
<script>
|
||||
const pasteButton = document.getElementById("paste-button");
|
||||
const urlField = document.getElementById("url");
|
||||
/**
|
||||
* @param content {Element}
|
||||
*/
|
||||
function setupPaste(content) {
|
||||
const pasteButton = content.querySelector("#paste-button");
|
||||
const urlField = content.querySelector("#url");
|
||||
|
||||
if (pasteButton) {
|
||||
pasteButton.addEventListener("click", async () => {
|
||||
try {
|
||||
const text = await navigator.clipboard.readText();
|
||||
|
@ -57,6 +65,10 @@
|
|||
toastr.error("Failed to paste url from clipboard.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
htmx.onLoad(setupPaste);
|
||||
</script>
|
||||
</body>
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
<footer class="footer mt-auto py-3 bg-body-tertiary" style="font-size: 0.95rem">
|
||||
<div class="container">
|
||||
<div class="row gap-2 gap-md-0">
|
||||
<div class="d-flex gap-4 col-md justify-content-center">
|
||||
<div class="d-flex gap-1 align-items-baseline">
|
||||
Version:
|
||||
<span class="text-muted">{{.Version}}</span>
|
||||
<span class="text-muted text-nowrap" style="font-size: smaller">(Build: {{.Build}})</span>
|
||||
</div>
|
||||
<div class="d-flex gap-1 align-items-baseline text-nowrap">
|
||||
yt-dlp version: <span class="text-muted">{{.BinaryVersion}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2 col-md justify-content-center">
|
||||
<a href="https://git.fifitido.net/apps/ytdl-web">Git Repository</a>
|
||||
<span class="text-muted">© 2024 FiFiTiDo</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
|
@ -1,23 +0,0 @@
|
|||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
|
@ -1,6 +0,0 @@
|
|||
dependencies:
|
||||
- name: common
|
||||
repository: https://bjw-s.github.io/helm-charts
|
||||
version: 1.4.0
|
||||
digest: sha256:4b75202a3971677362052bcee21a023ea42a0c18991800ae62a8890d4655b699
|
||||
generated: "2023-05-23T21:17:36.487449972-04:00"
|
|
@ -1,14 +0,0 @@
|
|||
apiVersion: v2
|
||||
description: A web-based frontend for yt-dlp
|
||||
name: ytdl-web
|
||||
version: 1.0.7
|
||||
kubeVersion: ">=1.22.0-0"
|
||||
type: application
|
||||
appVersion: 1.0.6
|
||||
maintainers:
|
||||
- name: fifitido
|
||||
email: me@fifitido.net
|
||||
dependencies:
|
||||
- name: common
|
||||
repository: https://bjw-s.github.io/helm-charts
|
||||
version: 1.4.0
|
|
@ -1,9 +0,0 @@
|
|||
{{- define "custom.custom.configuration.header" -}}
|
||||
## Custom configuration
|
||||
{{- end -}}
|
||||
|
||||
{{- define "custom.custom.configuration" -}}
|
||||
{{ template "custom.custom.configuration.header" . }}
|
||||
|
||||
N/A
|
||||
{{- end -}}
|
Binary file not shown.
|
@ -1,14 +0,0 @@
|
|||
---
|
||||
{{- include "bjw-s.common.loader.init" . }}
|
||||
|
||||
{{- define "ytdlp-web.hardcodedValues" -}}
|
||||
# Set the nameOverride based on the release name if no override has been set
|
||||
{{ if not .Values.global.nameOverride }}
|
||||
global:
|
||||
nameOverride: "{{ .Release.Name }}"
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
{{- $_ := mergeOverwrite .Values (include "ytdlp-web.hardcodedValues" . | fromYaml) -}}
|
||||
|
||||
{{/* Render the templates */}}
|
||||
{{ include "bjw-s.common.loader.generate" . }}
|
|
@ -1,39 +0,0 @@
|
|||
image:
|
||||
repository: git.fifitido.net/apps/ytdl-web
|
||||
pullPolicy: IfNotPresent
|
||||
tag: 1.0.6
|
||||
|
||||
strategy:
|
||||
type: Recreate
|
||||
|
||||
env:
|
||||
# YTDL_ENV: Production
|
||||
# YTDL_BINARY_PATH: yt-dlp
|
||||
YTDL_HTTP_LISTEN: 0.0.0.0
|
||||
YTDL_HTTP_PORT: 8080
|
||||
# YTDL_HTTP_BASEPATH: /example
|
||||
# YTDL_HTTP_TRUSTED_PROXIES: 127.0.0.1 10.0.0.0/8
|
||||
# YTDL_CACHE_TTL: 1h
|
||||
# YTDL_CACHE_DIRPATH: /tmp/ytdl-web
|
||||
YTDL_COOKIES_ENABLED: true
|
||||
YTDL_COOKIES_FILEPATH: /etc/ytdl-web/cookies.txt
|
||||
|
||||
service:
|
||||
main:
|
||||
ports:
|
||||
http:
|
||||
port: 8080
|
||||
|
||||
persistence:
|
||||
config:
|
||||
enabled: false
|
||||
mountPath: /etc/ytdl-web
|
||||
|
||||
ingress:
|
||||
main:
|
||||
enabled: false
|
||||
hosts:
|
||||
- host: ytdl-web.local
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Copyright © 2024 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// completionCmd represents the completion command
|
||||
var completionCmd = &cobra.Command{
|
||||
Use: "completion [bash|zsh|fish|powershell]",
|
||||
Short: "Generate completion script",
|
||||
Long: fmt.Sprintf(`To load completions:
|
||||
|
||||
Bash:
|
||||
|
||||
$ source <(%[1]s completion bash)
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
# Linux:
|
||||
$ %[1]s completion bash > /etc/bash_completion.d/%[1]s
|
||||
# macOS:
|
||||
$ %[1]s completion bash > $(brew --prefix)/etc/bash_completion.d/%[1]s
|
||||
|
||||
Zsh:
|
||||
|
||||
# If shell completion is not already enabled in your environment,
|
||||
# you will need to enable it. You can execute the following once:
|
||||
|
||||
$ echo "autoload -U compinit; compinit" >> ~/.zshrc
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
|
||||
|
||||
# You will need to start a new shell for this setup to take effect.
|
||||
|
||||
fish:
|
||||
|
||||
$ %[1]s completion fish | source
|
||||
|
||||
# To load completions for each session, execute once:
|
||||
$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
|
||||
|
||||
PowerShell:
|
||||
|
||||
PS> %[1]s completion powershell | Out-String | Invoke-Expression
|
||||
|
||||
# To load completions for every new session, run:
|
||||
PS> %[1]s completion powershell > %[1]s.ps1
|
||||
# and source this file from your PowerShell profile.
|
||||
`, rootCmd.Root().Name()),
|
||||
DisableFlagsInUseLine: true,
|
||||
ValidArgs: []string{"bash", "zsh", "fish", "powershell"},
|
||||
Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
switch args[0] {
|
||||
case "bash":
|
||||
cmd.Root().GenBashCompletion(os.Stdout)
|
||||
case "zsh":
|
||||
cmd.Root().GenZshCompletion(os.Stdout)
|
||||
case "fish":
|
||||
cmd.Root().GenFishCompletion(os.Stdout, true)
|
||||
case "powershell":
|
||||
cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(completionCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// completionCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// completionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
43
cmd/root.go
43
cmd/root.go
|
@ -1,15 +1,16 @@
|
|||
/*
|
||||
Copyright © 2023 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.fifitido.net/ytdl-web/config"
|
||||
"go.fifitido.net/ytdl-web/web"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
|
@ -20,23 +21,13 @@ var (
|
|||
rootCmd = &cobra.Command{
|
||||
Use: "ytdl-web",
|
||||
Short: "A web frontend for yt-dlp",
|
||||
Long: `YTDL Web
|
||||
|
||||
A web application that grabs the links to videos from over a
|
||||
thousand websites using the yt-dlp project under the hood.`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := web.Serve(cfg); err != nil {
|
||||
slog.Error("Error when serving website", slog.String("error", err.Error()))
|
||||
}
|
||||
},
|
||||
Long: `YTDL Web is a web application that grabs the links to videos
|
||||
from over a thousand websites using the yt-dlp project under the hood.`,
|
||||
}
|
||||
)
|
||||
|
||||
func Execute() {
|
||||
err := rootCmd.Execute()
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
func Execute() error {
|
||||
return rootCmd.Execute()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
@ -44,7 +35,7 @@ func init() {
|
|||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $XDG_CONFIG_HOME/ytdl-web/config.yml)")
|
||||
|
||||
rootCmd.PersistentFlags().IntP("port", "p", 0, "port to listen on")
|
||||
rootCmd.PersistentFlags().IntP("port", "p", 8080, "port to listen on")
|
||||
rootCmd.PersistentFlags().StringP("listen", "l", "", "address to listen on")
|
||||
rootCmd.PersistentFlags().StringP("base-path", "b", "", "the base path, used when behind reverse proxy")
|
||||
rootCmd.PersistentFlags().StringP("ytdlp-path", "y", "", "the path to the yt-dlp binary, used when it is not in $PATH")
|
||||
|
@ -69,14 +60,16 @@ func initConfig() {
|
|||
cfg, err = config.LoadConfig()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
slog.Error("Error loading configuration", slog.String("error", err.Error()))
|
||||
os.Exit(1)
|
||||
notFound := &viper.ConfigFileNotFoundError{}
|
||||
switch {
|
||||
case err != nil && !errors.As(err, notFound):
|
||||
cobra.CheckErr(err)
|
||||
case err != nil && errors.As(err, notFound):
|
||||
// The config file is optional, we shouldn't exit when the config is not found
|
||||
break
|
||||
default:
|
||||
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
|
||||
}
|
||||
|
||||
initLogging()
|
||||
|
||||
slog.Info("Configuration loaded")
|
||||
}
|
||||
|
||||
func initLogging() {
|
||||
|
@ -85,7 +78,7 @@ func initLogging() {
|
|||
if cfg.IsProduction() {
|
||||
handler = slog.HandlerOptions{
|
||||
AddSource: true,
|
||||
Level: slog.LevelWarn,
|
||||
Level: slog.LevelInfo,
|
||||
}.NewJSONHandler(os.Stdout)
|
||||
} else {
|
||||
handler = slog.HandlerOptions{
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.fifitido.net/ytdl-web/app/controllers"
|
||||
"go.fifitido.net/ytdl-web/pkg/server"
|
||||
"go.fifitido.net/ytdl-web/pkg/utils"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
var (
|
||||
serveCmd = &cobra.Command{
|
||||
Use: "serve",
|
||||
Short: "Serve the ytdl-web application",
|
||||
Long: `Serve the ytdl-web application`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
initLogging()
|
||||
logger := slog.Default()
|
||||
|
||||
db, err := badger.Open(
|
||||
badger.
|
||||
DefaultOptions(cfg.Cache.DirPath).
|
||||
WithLogger(utils.NewBadgerLogger(logger.With("module", "badger"))),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
cache := cache.NewDefaultMetadataCache(db)
|
||||
ytdl := ytdl.NewYtdl(cfg, slog.Default(), cache)
|
||||
|
||||
s := server.New(
|
||||
server.
|
||||
DefaultOptions().
|
||||
WithListenAddr(viper.GetString("http.listen")).
|
||||
WithListenPort(viper.GetInt("http.port")).
|
||||
WithLogger(logger.With("module", "server")),
|
||||
)
|
||||
|
||||
s.MountController("/", controllers.NewHomeController(ytdl))
|
||||
s.MountController("/download", controllers.NewDownloadController(ytdl))
|
||||
|
||||
return s.ListenAndServe()
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(serveCmd)
|
||||
|
||||
// Here you will define your flags and configuration settings.
|
||||
|
||||
// Cobra supports Persistent Flags which will work for this command
|
||||
// and all subcommands, e.g.:
|
||||
// completionCmd.PersistentFlags().String("foo", "", "A help for foo")
|
||||
|
||||
// Cobra supports local flags which will only run when this command
|
||||
// is called directly, e.g.:
|
||||
// completionCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
---
|
||||
# The server environment
|
||||
# For dev environments use Development
|
||||
# For prod environments use Production
|
||||
# For staging envronments use Staging
|
||||
env: Production
|
||||
# The path to the yt-dlp binary, if it is already in your $PATH just yt-dlp will work.
|
||||
# The path to the yt-dlp binary
|
||||
# If it is already in your $PATH just yt-dlp will work.
|
||||
binaryPath: yt-dlp
|
||||
http:
|
||||
# The port to listen on
|
||||
|
@ -29,7 +31,8 @@ cookies:
|
|||
# Settings for using cookies from a browser's cookies store
|
||||
fromBrowser:
|
||||
# The name of the browser to load cookies from.
|
||||
# Currently supported browsers are: brave, chrome, chromium, edge, firefox, opera, safari, vivaldi.
|
||||
# Currently supported browsers are: brave, chrome, chromium, edge,
|
||||
# firefox, opera, safari, vivaldi.
|
||||
browser: firefox
|
||||
|
||||
# The keyring used for decrypting Chromium cookies on Linux
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Env string `mapstructure:"env"`
|
||||
BinaryPath string `mapstructure:"binaryPath"`
|
||||
Ytdlp ConfigYtdlp `mapstructure:"ytdlp"`
|
||||
HTTP ConfigHTTP `mapstructure:"http"`
|
||||
Cache ConfigCache `mapstructure:"cache"`
|
||||
Cookies ConfigCookies `mapstructure:"cookies"`
|
||||
|
@ -27,6 +30,10 @@ func (c *Config) IsStaging() bool {
|
|||
return c.Env == "Staging"
|
||||
}
|
||||
|
||||
type ConfigYtdlp struct {
|
||||
BinaryPath string `mapstructure:"binaryPath"`
|
||||
}
|
||||
|
||||
type ConfigHTTP struct {
|
||||
Port int `mapstructure:"port"`
|
||||
Listen string `mapstructure:"listen"`
|
||||
|
@ -54,12 +61,13 @@ type ConfigCookiesFromBrowser struct {
|
|||
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Env: "Production",
|
||||
Ytdlp: ConfigYtdlp{BinaryPath: "yt-dlp"},
|
||||
HTTP: ConfigHTTP{
|
||||
Port: 8080,
|
||||
Listen: "127.0.0.1",
|
||||
BasePath: "/",
|
||||
},
|
||||
BinaryPath: "yt-dlp",
|
||||
Cache: ConfigCache{
|
||||
TTL: time.Hour,
|
||||
DirPath: "/tmp/ytdl-web",
|
||||
|
@ -73,34 +81,44 @@ func DefaultConfig() *Config {
|
|||
}
|
||||
|
||||
func LoadConfig(paths ...string) (*Config, error) {
|
||||
v := viper.New()
|
||||
viper.SetEnvPrefix("YTDL")
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
viper.AutomaticEnv()
|
||||
|
||||
v.SetEnvPrefix("YTDL")
|
||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
v.AutomaticEnv()
|
||||
|
||||
v.SetConfigName("config")
|
||||
v.SetConfigType("yaml")
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
|
||||
if len(paths) > 0 {
|
||||
for _, path := range paths {
|
||||
v.AddConfigPath(path)
|
||||
for _, p := range paths {
|
||||
viper.AddConfigPath(path.Dir(p))
|
||||
}
|
||||
} else {
|
||||
v.AddConfigPath(".")
|
||||
v.AddConfigPath("/etc/ytdl-web")
|
||||
v.AddConfigPath("$HOME/.config/ytdl-web")
|
||||
v.AddConfigPath("$XDG_CONFIG_HOME/ytdl-web")
|
||||
envDir := os.Getenv("YTDL_CONFIGDIR")
|
||||
if envDir != "" {
|
||||
viper.AddConfigPath(envDir)
|
||||
}
|
||||
|
||||
if err := v.ReadInConfig(); err != nil {
|
||||
viper.AddConfigPath(".")
|
||||
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err == nil {
|
||||
viper.AddConfigPath(homeDir + "/.config/ytdl-web")
|
||||
}
|
||||
|
||||
viper.AddConfigPath(xdg.ConfigHome + "/ytdl-web")
|
||||
for _, dir := range xdg.ConfigDirs {
|
||||
viper.AddConfigPath(dir + "/ytdl-web")
|
||||
}
|
||||
}
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
config := DefaultConfig()
|
||||
if err := v.Unmarshal(config); err != nil {
|
||||
if err := viper.Unmarshal(config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,156 @@
|
|||
{
|
||||
"nodes": {
|
||||
"devenv": {
|
||||
"locked": {
|
||||
"dir": "src/modules",
|
||||
"lastModified": 1708141957,
|
||||
"narHash": "sha256-IWkw+jsVpu7HFNPbOTJaQeMYQ5/eh7ZVScPvtlSo8vc=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "40b567388381137a3c49acdff5f4b6946d645a5f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "src/modules",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1703887061,
|
||||
"narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1708151420,
|
||||
"narHash": "sha256-MGT/4aGCWQPQiu6COqJdCj9kSpLPiShgbwpbC38YXC8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "6e2f00c83911461438301db0dba5281197fe4b3a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1704874635,
|
||||
"narHash": "sha256-YWuCrtsty5vVZvu+7BchAxmcYzTMfolSPP5io8+WYCg=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3dc440faeee9e889fe2d1b4d25ad0f430d449356",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-23.11",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"flake-utils": "flake-utils",
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708018599,
|
||||
"narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
allowUnfree: true
|
||||
inputs:
|
||||
nixpkgs:
|
||||
url: github:NixOS/nixpkgs/nixpkgs-unstable
|
|
@ -0,0 +1,757 @@
|
|||
{
|
||||
"nodes": {
|
||||
"cachix": {
|
||||
"inputs": {
|
||||
"devenv": "devenv_2",
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"git-hooks": [
|
||||
"devenv",
|
||||
"pre-commit-hooks"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726520618,
|
||||
"narHash": "sha256-jOsaBmJ/EtX5t/vbylCdS7pWYcKGmWOKg4QKUzKr6dA=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "695525f9086542dfb09fde0871dbf4174abbf634",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"cachix_2": {
|
||||
"inputs": {
|
||||
"devenv": "devenv_3",
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712055811,
|
||||
"narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "cachix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv": {
|
||||
"inputs": {
|
||||
"cachix": "cachix",
|
||||
"flake-compat": "flake-compat_2",
|
||||
"nix": "nix_3",
|
||||
"nixpkgs": "nixpkgs_3",
|
||||
"pre-commit-hooks": "pre-commit-hooks_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730890834,
|
||||
"narHash": "sha256-ogmpmsPOlX4qeWVW4NZkTd0Lx8V4rvnjwlgOX7WnTZo=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "c5353d1a0483b8f0dc15933de91c6b1b9a892831",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv_2": {
|
||||
"inputs": {
|
||||
"cachix": "cachix_2",
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"nix": "nix_2",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"nixpkgs"
|
||||
],
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"git-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1723156315,
|
||||
"narHash": "sha256-0JrfahRMJ37Rf1i0iOOn+8Z4CLvbcGNwa2ChOAVrp/8=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "ff5eb4f2accbcda963af67f1a1159e3f6c7f5f91",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"devenv_3": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"cachix",
|
||||
"flake-compat"
|
||||
],
|
||||
"nix": "nix",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix",
|
||||
"pre-commit-hooks": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"cachix",
|
||||
"pre-commit-hooks"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1708704632,
|
||||
"narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv",
|
||||
"rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "python-rewrite",
|
||||
"repo": "devenv",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1673956053,
|
||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-compat_2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1696426674,
|
||||
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "edolstra",
|
||||
"repo": "flake-compat",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-parts_2": {
|
||||
"inputs": {
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730504689,
|
||||
"narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "506278e768c2a08bec68eb62932193e341f55c90",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "flake-parts",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1689068808,
|
||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1667395993,
|
||||
"narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_3": {
|
||||
"inputs": {
|
||||
"systems": "systems_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gitignore": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"pre-commit-hooks",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1709087332,
|
||||
"narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "hercules-ci",
|
||||
"repo": "gitignore.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"libgit2": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1697646580,
|
||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "libgit2",
|
||||
"repo": "libgit2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"mk-shell-bin": {
|
||||
"locked": {
|
||||
"lastModified": 1677004959,
|
||||
"narHash": "sha256-/uEkr1UkJrh11vD02aqufCxtbF5YnhRTIKlx5kyvf+I=",
|
||||
"owner": "rrbutani",
|
||||
"repo": "nix-mk-shell-bin",
|
||||
"rev": "ff5d8bd4d68a347be5042e2f16caee391cd75887",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rrbutani",
|
||||
"repo": "nix-mk-shell-bin",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix": {
|
||||
"inputs": {
|
||||
"flake-compat": "flake-compat",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix-github-actions": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"poetry2nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1688870561,
|
||||
"narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "nix-github-actions",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix2container": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_3",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1730479402,
|
||||
"narHash": "sha256-79NLeNjpCa4mSasmFsE3QA6obURezF0TUO5Pm+1daog=",
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"rev": "5fb215a1564baa74ce04ad7f903d94ad6617e17a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nlewo",
|
||||
"repo": "nix2container",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-regression": "nixpkgs-regression_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712911606,
|
||||
"narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.21",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nix_3": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"flake-parts": "flake-parts",
|
||||
"libgit2": "libgit2",
|
||||
"nixpkgs": "nixpkgs_2",
|
||||
"nixpkgs-23-11": "nixpkgs-23-11",
|
||||
"nixpkgs-regression": "nixpkgs-regression_3",
|
||||
"pre-commit-hooks": "pre-commit-hooks"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1727438425,
|
||||
"narHash": "sha256-X8ES7I1cfNhR9oKp06F6ir4Np70WGZU5sfCOuNBEwMg=",
|
||||
"owner": "domenkozar",
|
||||
"repo": "nix",
|
||||
"rev": "f6c5ae4c1b2e411e6b1e6a8181cc84363d6a7546",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "domenkozar",
|
||||
"ref": "devenv-2.24",
|
||||
"repo": "nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1692808169,
|
||||
"narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-23-11": {
|
||||
"locked": {
|
||||
"lastModified": 1717159533,
|
||||
"narHash": "sha256-oamiKNfr2MS6yH64rUn99mIZjc45nGJlj9eGth/3Xuw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "a62e6edd6d5e1fa0329b8653c801147986f8d446",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"lastModified": 1730504152,
|
||||
"narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=",
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
||||
},
|
||||
"original": {
|
||||
"type": "tarball",
|
||||
"url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression_2": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-regression_3": {
|
||||
"locked": {
|
||||
"lastModified": 1643052045,
|
||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-stable": {
|
||||
"locked": {
|
||||
"lastModified": 1720386169,
|
||||
"narHash": "sha256-NGKVY4PjzwAa4upkGtAMz1npHGoRzWotlSnVlqI40mo=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "194846768975b7ad2c4988bdb82572c00222c0d7",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1717432640,
|
||||
"narHash": "sha256-+f9c4/ZX5MWDOuB1rKoWj+lBNm0z0rs4CK47HBLxy1o=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "88269ab3044128b7c2f4c7d68448b2fb50456870",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "release-24.05",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_3": {
|
||||
"locked": {
|
||||
"lastModified": 1716977621,
|
||||
"narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_4": {
|
||||
"locked": {
|
||||
"lastModified": 1716977621,
|
||||
"narHash": "sha256-Q1UQzYcMJH4RscmpTkjlgqQDX5yi1tZL0O345Ri6vXQ=",
|
||||
"owner": "cachix",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"rev": "4267e705586473d3e5c8d50299e71503f16a6fb6",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"ref": "rolling",
|
||||
"repo": "devenv-nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"poetry2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-github-actions": "nix-github-actions",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"cachix",
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1692876271,
|
||||
"narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"nix"
|
||||
],
|
||||
"flake-utils": "flake-utils_2",
|
||||
"gitignore": [
|
||||
"devenv",
|
||||
"nix"
|
||||
],
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": [
|
||||
"devenv",
|
||||
"nix",
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1712897695,
|
||||
"narHash": "sha256-nMirxrGteNAl9sWiOhoN5tIHyjBbVi5e2tgZUgZlK3Y=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "40e6053ecb65fcbf12863338a6dcefb3f55f1bf8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"pre-commit-hooks_2": {
|
||||
"inputs": {
|
||||
"flake-compat": [
|
||||
"devenv",
|
||||
"flake-compat"
|
||||
],
|
||||
"gitignore": "gitignore",
|
||||
"nixpkgs": [
|
||||
"devenv",
|
||||
"nixpkgs"
|
||||
],
|
||||
"nixpkgs-stable": "nixpkgs-stable"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1726745158,
|
||||
"narHash": "sha256-D5AegvGoEjt4rkKedmxlSEmC+nNLMBPWFxvmYnVLhjk=",
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"rev": "4e743a6920eab45e8ba0fbe49dc459f1423a4b74",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "cachix",
|
||||
"repo": "pre-commit-hooks.nix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"devenv": "devenv",
|
||||
"flake-parts": "flake-parts_2",
|
||||
"mk-shell-bin": "mk-shell-bin",
|
||||
"nix2container": "nix2container",
|
||||
"nixpkgs": "nixpkgs_4"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems_2": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
description = "Description for the project";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:cachix/devenv-nixpkgs/rolling";
|
||||
devenv.url = "github:cachix/devenv";
|
||||
nix2container.url = "github:nlewo/nix2container";
|
||||
nix2container.inputs.nixpkgs.follows = "nixpkgs";
|
||||
mk-shell-bin.url = "github:rrbutani/nix-mk-shell-bin";
|
||||
};
|
||||
|
||||
nixConfig = {
|
||||
extra-trusted-public-keys = "devenv.cachix.org-1:w1cLUi8dv3hnoSPGAuibQv+f9TZLr6cv/Hm9XgU50cw=";
|
||||
extra-substituters = "https://devenv.cachix.org";
|
||||
};
|
||||
|
||||
outputs = inputs@{ self, flake-parts, ... }:
|
||||
let
|
||||
version = "1.2.0";
|
||||
rev = if (self ? rev) then self.rev else self.dirtyRev;
|
||||
in
|
||||
flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
imports = [
|
||||
inputs.devenv.flakeModule
|
||||
];
|
||||
systems = [ "x86_64-linux" "i686-linux" "x86_64-darwin" "aarch64-linux" "aarch64-darwin" ];
|
||||
|
||||
perSystem = { config, self', inputs', pkgs, system, ... }: {
|
||||
# Per-system attributes can be defined here. The self' and inputs'
|
||||
# module parameters provide easy access to attributes of the same
|
||||
# system.
|
||||
|
||||
# needed for devenv up
|
||||
packages.devenv-up = self'.devShells.default.config.procfileScript;
|
||||
|
||||
packages.default = pkgs.callPackage ./nix/package.nix { inherit rev version; };
|
||||
|
||||
devenv.shells.default = {
|
||||
name = "ytdl-web";
|
||||
|
||||
imports = [
|
||||
./nix/devenv.nix
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
flake = {
|
||||
# The usual flake attributes can be defined here, including system-
|
||||
# agnostic ones like nixosModule and system-enumerating ones, although
|
||||
# those are more easily expressed in perSystem.
|
||||
|
||||
nixosModules.default = import ./nix/module.nix;
|
||||
};
|
||||
};
|
||||
}
|
25
go.mod
25
go.mod
|
@ -1,22 +1,18 @@
|
|||
module go.fifitido.net/ytdl-web
|
||||
|
||||
go 1.20
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/adrg/xdg v0.4.0
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4
|
||||
github.com/gofiber/fiber/v2 v2.44.0
|
||||
github.com/gofiber/template v1.8.0
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73
|
||||
github.com/samber/lo v1.38.1
|
||||
github.com/samber/slog-fiber v0.1.0
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/viper v1.10.0
|
||||
github.com/sujit-baniya/flash v0.1.8
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 // indirect
|
||||
|
@ -24,34 +20,25 @@ require (
|
|||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/klauspost/compress v1.16.3 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.18 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.14 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/philhofer/fwd v1.1.2 // indirect
|
||||
github.com/pkg/errors v0.8.1 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tinylib/msgp v1.1.8 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.45.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.7.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
gopkg.in/ini.v1 v1.66.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
|
799
go.sum
799
go.sum
|
@ -1,109 +1,15 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
|
||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls=
|
||||
github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/cbroglie/mustache v1.4.0/go.mod h1:SS1FTIghy0sjse4DUVGV1k/40B1qE1XkD9DtDsHo9iM=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -117,285 +23,65 @@ github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczC
|
|||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.1/go.mod h1:AY7fTTXNdv/aJ2O5jwpxAPOWUZ7hQAEvzN5Pf27BkQQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gofiber/fiber/v2 v2.36.0/go.mod h1:tgCr+lierLwLoVHHO/jn3Niannv34WRkQETU8wiL9fQ=
|
||||
github.com/gofiber/fiber/v2 v2.43.0/go.mod h1:mpS1ZNE5jU+u+BA4FbM+KKnUzJ4wzTK+FT2tG3tU+6I=
|
||||
github.com/gofiber/fiber/v2 v2.44.0 h1:Z90bEvPcJM5GFJnu1py0E1ojoerkyew3iiNJ78MQCM8=
|
||||
github.com/gofiber/fiber/v2 v2.44.0/go.mod h1:VTMtb/au8g01iqvHyaCzftuM/xmZgKOZCtFzz6CdV9w=
|
||||
github.com/gofiber/template v1.8.0 h1:jOn9RhxYO7rHTHGLNRpYfDoVm8b5GH/dtl15ZT5NifE=
|
||||
github.com/gofiber/template v1.8.0/go.mod h1:jf2w+ioGUS5swf5C/VK+FyE+DI19uz+vXHCX/TIAxIk=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
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.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M=
|
||||
github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
|
||||
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
|
||||
github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
|
||||
github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
|
||||
github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
|
||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73 h1:Shcv21tstWAyUkKxbn5bTARYej9sgEgFgTRxUPk1J8o=
|
||||
github.com/htfy96/reformism v0.0.0-20160819020323-e5bfca398e73/go.mod h1:i2jduFeVras6pm8GnBWdfVKj97mGEXJogjMHzyJhukY=
|
||||
github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47ZCWhYzw7ho=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
|
||||
github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
|
||||
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
|
||||
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-slim v0.0.4/go.mod h1:kXIwPrQbAZrhungtweoDO6qQQpUem6XkBg/mXykpoO0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
|
||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
|
||||
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM=
|
||||
github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA=
|
||||
github.com/samber/slog-fiber v0.1.0 h1:Cr8i3VNzpsbPCUfHPP7h+jLAvkyhtZpxJtr497TZ9vI=
|
||||
github.com/samber/slog-fiber v0.1.0/go.mod h1:hhMSY9n07NWwl8vf7VAs1tPsz5LqS/ijBpQWZK0a0xw=
|
||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
|
||||
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
|
||||
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
|
||||
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA=
|
||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
|
@ -408,523 +94,50 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM
|
|||
github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk=
|
||||
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
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.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/sujit-baniya/flash v0.1.8 h1:BwcrybCatPU30VMA9IBA5q3ZE0VSr5c7qTqwZrSvyRI=
|
||||
github.com/sujit-baniya/flash v0.1.8/go.mod h1:kmlAIkLDMlLshEeeE6fETEW8kSOopKN5WA3KXLmS/U0=
|
||||
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
|
||||
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
|
||||
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
|
||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.38.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I=
|
||||
github.com/valyala/fasthttp v1.45.0 h1:zPkkzpIn8tdHZUrVa6PzYd0i5verqiPSkgTd3bSUcpA=
|
||||
github.com/valyala/fasthttp v1.45.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.1/go.mod h1:pMEacxZW7o8pg4CrFE7pquyCJJzZvkvdD2RibOCCCGs=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
|
||||
golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
|
||||
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.5.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.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211008145708-270636b82663/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211028162531-8db9c33dc351/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
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.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
|
||||
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
13
main.go
13
main.go
|
@ -1,11 +1,16 @@
|
|||
/*
|
||||
Copyright © 2023 NAME HERE <EMAIL ADDRESS>
|
||||
|
||||
Copyright © 2024 Evan Fiordeliso <evan.fiordeliso@gmail.com>
|
||||
*/
|
||||
package main
|
||||
|
||||
import "go.fifitido.net/ytdl-web/cmd"
|
||||
import (
|
||||
"os"
|
||||
|
||||
"go.fifitido.net/ytdl-web/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cmd.Execute()
|
||||
if err := cmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
{ pkgs, ... }:
|
||||
|
||||
{
|
||||
# https://devenv.sh/basics/
|
||||
env.NAME = "ytdl-web";
|
||||
env.BINARY_OUT = "./out/ytdl-web";
|
||||
env.VERSION = "v1.2.3";
|
||||
env.VERSION_PKG = "go.fifitido.net/ytdl-web/version";
|
||||
env.DOCKER_REGISTRY = "git.fifitido.net";
|
||||
env.DOCKER_ORG = "apps";
|
||||
env.DOCKER_PLATFORMS = "linux/amd64,linux/arm64";
|
||||
|
||||
env.YTDL_ENV = "Development";
|
||||
|
||||
# https://devenv.sh/packages/
|
||||
packages = with pkgs; [
|
||||
git
|
||||
air
|
||||
goreleaser
|
||||
docker
|
||||
docker-compose
|
||||
buildkit
|
||||
docker-buildx
|
||||
yt-dlp
|
||||
cobra-cli
|
||||
];
|
||||
|
||||
# https://devenv.sh/scripts/
|
||||
scripts.deps.exec = "go mod download";
|
||||
scripts.tidy.exec = "go mod tidy";
|
||||
scripts.check.exec = "goreleaser check";
|
||||
|
||||
scripts.build-id.exec = "git rev-parse --short HEAD";
|
||||
scripts.build-date.exec = "date -Iseconds";
|
||||
|
||||
scripts.build.exec = ''
|
||||
go build -ldflags="
|
||||
-X $VERSION_PKG.Version=$VERSION
|
||||
-X $VERSION_PKG.Build=$(build-id)
|
||||
-X $VERSION_PKG.BuildDate=$(build-date)
|
||||
-X $VERSION_PKG.BuiltBy=manual
|
||||
" -o $BINARY_OUT .
|
||||
'';
|
||||
scripts.clean.exec = ''
|
||||
rm -rf ./dist/ ./out/ ./tmp/
|
||||
go clean
|
||||
'';
|
||||
scripts.release.exec = ''
|
||||
clean
|
||||
goreleaser release
|
||||
docker-build-release
|
||||
'';
|
||||
scripts.lint.exec = "trunk check";
|
||||
scripts.fmt.exec = "trunk fmt";
|
||||
|
||||
scripts.docker-image.exec = "echo $DOCKER_REGISTRY/$DOCKER_ORG/$NAME";
|
||||
|
||||
scripts.docker-init.exec = ''
|
||||
docker buildx create \
|
||||
--name $NAME \
|
||||
--platform $DOCKER_PLATFORMS
|
||||
'';
|
||||
|
||||
scripts.docker-login.exec = "docker login $DOCKER_REGISTRY";
|
||||
|
||||
scripts.docker-build.exec = ''
|
||||
platform=''${1:-linux}
|
||||
output=''${2:-type=docker}
|
||||
|
||||
docker-init
|
||||
PROGRESS_NO_TRUNC=1 docker buildx build . \
|
||||
--tag $(docker-image):$VERSION \
|
||||
--tag $(docker-image):latest \
|
||||
--platform $platform \
|
||||
--builder $NAME \
|
||||
--build-arg VERSION=$VERSION \
|
||||
--build-arg BUILD=$(build-id) \
|
||||
--build-arg BUILD_DATE=$(build-date) \
|
||||
--build-arg BUILT_BY="Devenv Script" \
|
||||
--progress plain \
|
||||
--output $output
|
||||
'';
|
||||
|
||||
scripts.docker-build-release.exec = "docker-build $DOCKER_PLATFORMS type=image,push=true";
|
||||
|
||||
enterShell = ''
|
||||
echo "Welcome to the $NAME development environment."
|
||||
echo -n "Golang version: $(go version | cut -d ' ' -f 3), "
|
||||
echo -n "Goreleaser version: $(goreleaser --version | tail -n 9 | head -n 1 | cut -c 16-), "
|
||||
echo -n "Docker CLI version: $(docker version -f {{.Client.Version}}), "
|
||||
echo -n "Buildx version: $(docker buildx version | cut -d ' ' -f 2), "
|
||||
echo "yt-dlp version: $(yt-dlp --version)"
|
||||
'';
|
||||
|
||||
# https://devenv.sh/languages/
|
||||
languages.go.enable = true;
|
||||
|
||||
# https://devenv.sh/pre-commit-hooks/
|
||||
pre-commit.hooks.staticcheck.enable = true;
|
||||
pre-commit.hooks.hadolint.enable = true;
|
||||
pre-commit.hooks.yamllint.enable = true;
|
||||
|
||||
# https://devenv.sh/processes/
|
||||
processes.web.exec = "air";
|
||||
|
||||
# See full reference at https://devenv.sh/reference/options/
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
{ config, lib, pkgs, ... }:
|
||||
let
|
||||
inherit (lib.options) mkOption mkEnableOption mkPackageOption;
|
||||
inherit (lib.modules) mkIf;
|
||||
inherit (lib.types) str enum int path submodule nullOr bool;
|
||||
|
||||
cfg = config.services.ytdl-web;
|
||||
in
|
||||
{
|
||||
options.services.ytdl-web = {
|
||||
enable = mkEnableOption "ytdl-web";
|
||||
package = mkPackageOption pkgs "ytdl-web" { };
|
||||
|
||||
user = mkOption {
|
||||
type = str;
|
||||
default = "ytdl-web";
|
||||
description = ''
|
||||
The user account ytdl-web will run under.
|
||||
'';
|
||||
};
|
||||
|
||||
group = mkOption {
|
||||
type = str;
|
||||
default = "ytdl-web";
|
||||
description = ''
|
||||
The group ytdl-web will run under.
|
||||
'';
|
||||
};
|
||||
|
||||
appEnvironment = mkOption {
|
||||
type = enum [ "Development" "Staging" "Production" ];
|
||||
default = "Production";
|
||||
description = ''
|
||||
The application environment mode.
|
||||
'';
|
||||
};
|
||||
|
||||
ytdlPackage = mkPackageOption pkgs "yt-dlp" { };
|
||||
|
||||
port = mkOption {
|
||||
type = int;
|
||||
default = 8080;
|
||||
description = ''
|
||||
The tcp port for the web server to listen on.
|
||||
'';
|
||||
};
|
||||
|
||||
listen = mkOption {
|
||||
type = str;
|
||||
default = "0.0.0.0";
|
||||
example = "127.0.0.1";
|
||||
description = ''
|
||||
The address for the web server to listen on.
|
||||
'';
|
||||
};
|
||||
|
||||
openFirewall = mkOption {
|
||||
type = bool;
|
||||
default = false;
|
||||
example = literalExpression "true";
|
||||
description = ''
|
||||
Open ports in the firewall for the ytdl-web server.
|
||||
'';
|
||||
};
|
||||
|
||||
basePath = mkOption {
|
||||
type = str;
|
||||
default = "/";
|
||||
example = "/ytdl-web";
|
||||
description = ''
|
||||
The base path that the web application is hosted under.
|
||||
Useful for reverse-proxies that proxy the app with a path prefix.
|
||||
'';
|
||||
};
|
||||
|
||||
cacheTTL = mkOption {
|
||||
type = str;
|
||||
default = "1h";
|
||||
example = "2m";
|
||||
description = ''
|
||||
How long to keep cached metadata for.
|
||||
|
||||
A duration string is a possibly signed sequence of decimal numbers,
|
||||
each with optional fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
|
||||
Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".
|
||||
'';
|
||||
};
|
||||
|
||||
cacheDir = mkOption {
|
||||
type = path;
|
||||
default = "/var/cache/ytdl-web";
|
||||
example = "/tmp/ytdl-web";
|
||||
description = ''
|
||||
The directory containing the ytdl metadata cache.
|
||||
'';
|
||||
};
|
||||
|
||||
cookies = mkOption {
|
||||
type = submodule {
|
||||
options = {
|
||||
enable = mkEnableOption "ytdl cookies";
|
||||
|
||||
file = mkOption {
|
||||
type = nullOr path;
|
||||
default = null;
|
||||
example = "/etc/ytdl-web/cookies.txt";
|
||||
description = ''
|
||||
The file that contains the netscape formatted cookies.
|
||||
'';
|
||||
};
|
||||
|
||||
fromBrowser = mkOption {
|
||||
description = ''
|
||||
Settings for obtaining cookies from a local browser's cookie storage.
|
||||
'';
|
||||
|
||||
type = submodule {
|
||||
options = {
|
||||
browser = mkOption {
|
||||
type = nullOr (enum [ "brave" "chrome" "chromium" "edge" "firefox" "opera" "safari" "vivaldi" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
The name of the browser to load cookies from.
|
||||
'';
|
||||
};
|
||||
|
||||
keyring = mkOption {
|
||||
type = nullOr (enum [ "basictext" "gnomekeyring" "kwallet" ]);
|
||||
default = null;
|
||||
description = ''
|
||||
The name of the keyring to use to decrypt cookies when using the chromium browser.
|
||||
'';
|
||||
};
|
||||
|
||||
profile = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
The name of the browser profile to load the cookies from.
|
||||
'';
|
||||
};
|
||||
|
||||
container = mkOption {
|
||||
type = nullOr str;
|
||||
default = null;
|
||||
description = ''
|
||||
The container name to load the cookies from when using the firefox browser.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = cfg.cookies.file != null && cfg.cookies.fromBrowser.browser != null;
|
||||
message = "The `services.ytdl-web.cookies.file` and `services.ytdl-web.cookies.fromBrowser.browser` options are mutually exclusive.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.cookies.fromBrowser.browser != null &&
|
||||
!(builtins.elem cfg.cookies.fromBrowser.browser [ "brave" "chrome" "chromium" "edge" "opera" "vivaldi" ]) &&
|
||||
cfg.cookies.fromBrowser.keyring != null;
|
||||
message = "The `services.ytdl-web.cookies.fromBrowser.keyring` only functions with a chromium-based browser.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.cookies.fromBrowser.browser != null &&
|
||||
cfg.cookies.fromBrowser.browser != "firefox" &&
|
||||
cfg.cookies.fromBrowser.container != null;
|
||||
message = "The `services.ytdl-web.cookies.fromBrowser.container` only functions with the firefox browser.";
|
||||
}
|
||||
];
|
||||
|
||||
systemd.services.ytdl-web = {
|
||||
description = "ytdl-web";
|
||||
after = [ "networking.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
environment = {
|
||||
YTDL_ENV = cfg.appEnvironment;
|
||||
YTDL_BINARY_PATH = toString cfg.ytdlPackage;
|
||||
YTDL_HTTP_PORT = toString cfg.port;
|
||||
YTDL_HTTP_LISTEN = cfg.listen;
|
||||
YTDL_HTTP_BASEPATH = cfg.basePath;
|
||||
YTDL_CACHE_TTL = cfg.cacheTTL;
|
||||
YTDL_CACHE_DIRPATH = cfg.cacheDir;
|
||||
YTDL_COOKIES_ENABLED = if cfg.cookies.enable then "true" else "false";
|
||||
YTDL_COOKIES_FILEPATH = cfg.cookies.file;
|
||||
YTDL_COOKIES_FROMBROWSER_BROWSER = cfg.cookies.fromBrowser.browser;
|
||||
YTDL_COOKIES_FROMBROWSER_KEYRING = cfg.cookies.fromBrowser.keyring;
|
||||
YTDL_COOKIES_FROMBROWSER_PROFILE = cfg.cookies.fromBrowser.profile;
|
||||
YTDL_COOKIES_FROMBROWSER_CONTAINER = cfg.cookies.fromBrowser.container;
|
||||
};
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = cfg.user;
|
||||
Group = cfg.group;
|
||||
ExecStart = "${lib.getExe cfg.package} serve";
|
||||
Restart = "on-failure";
|
||||
};
|
||||
};
|
||||
|
||||
systemd.tmpfiles.rules = [
|
||||
"d ${cfg.cacheDir} 0770 ${cfg.user} ${cfg.group} -"
|
||||
];
|
||||
|
||||
networking.firewall = mkIf cfg.openFirewall {
|
||||
allowedTCPPorts = [ cfg.port ];
|
||||
};
|
||||
|
||||
users = {
|
||||
users = mkIf (cfg.user == "ytdl-web") {
|
||||
ytdl-web = {
|
||||
isSystemUser = true;
|
||||
group = cfg.group;
|
||||
};
|
||||
};
|
||||
|
||||
groups = mkIf (cfg.group == "ytdl-web") {
|
||||
ytdl-web = { };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
{ buildGoModule
|
||||
, installShellFiles
|
||||
, lib
|
||||
, rev
|
||||
, version
|
||||
, ...
|
||||
}:
|
||||
buildGoModule rec {
|
||||
pname = "ytdl-web";
|
||||
inherit version;
|
||||
|
||||
src = ./..;
|
||||
|
||||
vendorHash = "sha256-Rqh5tGcSey53e0Ln3u5agvOwRJ6/I1eUpzRylwtjhQo=";
|
||||
|
||||
ldflags = [
|
||||
"-s"
|
||||
"-w"
|
||||
"-X $VERSION_PKG.Version=${version}"
|
||||
"-X $VERSION_PKG.Build=${rev}"
|
||||
"-X $VERSION_PKG.BuildDate=1970-01-01T0:00:00+0000"
|
||||
"-X $VERSION_PKG.BuiltBy=nix"
|
||||
];
|
||||
|
||||
nativeBuildInputs = [ installShellFiles ];
|
||||
|
||||
postInstall = ''
|
||||
installShellCompletion --cmd ${pname} \
|
||||
--zsh <($out/bin/${pname} completion zsh) \
|
||||
--bash <($out/bin/${pname} completion bash) \
|
||||
--fish <($out/bin/${pname} completion fish)
|
||||
'';
|
||||
|
||||
meta = with lib; {
|
||||
description = "Yet another yt-dlp web frontend written in Go.";
|
||||
homepage = "https://git.fifitido.net/apps/ytdl-web";
|
||||
license = licenses.gpl3Only;
|
||||
mainProgram = "ytdl-web";
|
||||
};
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package htmx
|
||||
|
||||
import "net/http"
|
||||
|
||||
type HTMX struct {
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
}
|
||||
|
||||
func New(w http.ResponseWriter, r *http.Request) *HTMX {
|
||||
return &HTMX{
|
||||
w: w,
|
||||
r: r,
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Request header methods
|
||||
//
|
||||
|
||||
// True when the request is an HTMX request
|
||||
func (h *HTMX) IsHtmxRequest() bool {
|
||||
return h.r.Header.Get("HX-Request") == "true"
|
||||
}
|
||||
|
||||
// Indicates that the request is via an element using hx-boost
|
||||
func (h *HTMX) IsBoosted() bool {
|
||||
return h.r.Header.Get("HX-Boosted") == "true"
|
||||
}
|
||||
|
||||
// The current URL of the browser
|
||||
func (h *HTMX) CurrentUrl() string {
|
||||
return h.r.Header.Get("HX-Current-URL")
|
||||
}
|
||||
|
||||
// If the request is for history restoration after a miss in the local history cache
|
||||
func (h *HTMX) IsHistoryRestore() bool {
|
||||
return h.r.Header.Get("HX-History-Restore") == "true"
|
||||
}
|
||||
|
||||
// The id of the element that triggered the request
|
||||
func (h *HTMX) TriggerId() string {
|
||||
return h.r.Header.Get("HX-Trigger")
|
||||
}
|
||||
|
||||
// The name of the element that triggered the request
|
||||
func (h *HTMX) TriggerName() string {
|
||||
return h.r.Header.Get("HX-Trigger-Name")
|
||||
}
|
||||
|
||||
// The id of the target element
|
||||
func (h *HTMX) TargetId() string {
|
||||
return h.r.Header.Get("HX-Target")
|
||||
}
|
||||
|
||||
// The value entered by the user when prompted via hx-prompt
|
||||
func (h *HTMX) Prompt() string {
|
||||
return h.r.Header.Get("HX-Prompt")
|
||||
}
|
||||
|
||||
//
|
||||
// Response header methods
|
||||
//
|
||||
|
||||
// Pushe a new url into the history stack
|
||||
func (h *HTMX) PushUrl(url string) {
|
||||
h.w.Header().Set("HX-Push", url)
|
||||
}
|
||||
|
||||
// Trigger a client-side redirect to a new location
|
||||
func (h *HTMX) RedirectTo(url string) {
|
||||
h.w.Header().Set("HX-Redirect", url)
|
||||
}
|
||||
|
||||
// Triggers a client-side redirect to a new location that acts as a swap
|
||||
func (h *HTMX) Location(url string) {
|
||||
h.w.Header().Set("Location", url)
|
||||
}
|
||||
|
||||
// Replace the current URL in the location bar
|
||||
func (h *HTMX) ReplaceUrl(url string) {
|
||||
h.w.Header().Set("HX-Replace-Url", url)
|
||||
}
|
||||
|
||||
// Sets refresh to true causing the client side to do a full refresh of the page
|
||||
func (h *HTMX) Refresh() {
|
||||
h.w.Header().Set("HX-Refresh", "true")
|
||||
}
|
||||
|
||||
// Trigger client side events
|
||||
func (h *HTMX) Trigger(name string) {
|
||||
h.w.Header().Set("HX-Trigger", name)
|
||||
}
|
||||
|
||||
// Trigger client side events after the swap step
|
||||
func (h *HTMX) TriggerAfterSwap(name string) {
|
||||
h.w.Header().Set("HX-Trigger-After-Swap", name)
|
||||
}
|
||||
|
||||
// Trigger client side events after the settle step
|
||||
func (h *HTMX) TriggerAfterSettle(name string) {
|
||||
h.w.Header().Set("HX-Trigger-After-Settle", name)
|
||||
}
|
||||
|
||||
// Specify how the response will be swapped. See hx-swap for possible values
|
||||
func (h *HTMX) Reswap(value string) {
|
||||
h.w.Header().Set("HX-Reswap", value)
|
||||
}
|
||||
|
||||
// Update the target of the content update to a different element on the page
|
||||
// Value should be a CSS selector.
|
||||
func (h *HTMX) Retarget(value string) {
|
||||
h.w.Header().Set("HX-Retarget", value)
|
||||
}
|
||||
|
||||
// Choose which part of the response is used to be swapped in. Overrides an existing hx-select on the triggering element.
|
||||
// Value should be a CSS selector.
|
||||
func (h *HTMX) Reselect(value string) {
|
||||
h.w.Header().Set("HX-Reselect", value)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package httpx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrQueryKeyNotFound = errors.New("query key not found")
|
||||
)
|
||||
|
||||
func Query(r *http.Request, key string) (string, error) {
|
||||
values, ok := r.URL.Query()[key]
|
||||
if !ok || len(values) == 0 {
|
||||
return "", ErrQueryKeyNotFound
|
||||
}
|
||||
|
||||
return values[0], nil
|
||||
}
|
||||
|
||||
func QueryInt(r *http.Request, key string) (int, error) {
|
||||
value, err := Query(r, key)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return strconv.Atoi(value)
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package middlewarex
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
func SlogRequestLogger(logger *slog.Logger) func(next http.Handler) http.Handler {
|
||||
if logger == nil {
|
||||
return func(next http.Handler) http.Handler { return next }
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
ww := middleware.NewWrapResponseWriter(w, r.ProtoMajor)
|
||||
ti := time.Now()
|
||||
|
||||
defer func() {
|
||||
reqLogger := logger.With(
|
||||
slog.String("proto", r.Proto),
|
||||
slog.String("path", r.URL.Path),
|
||||
slog.String("reqId", middleware.GetReqID(r.Context())),
|
||||
slog.Duration("lat", time.Since(ti)),
|
||||
slog.Int("status", ww.Status()),
|
||||
slog.Int("size", ww.BytesWritten()),
|
||||
)
|
||||
|
||||
reqLogger.Info("Served")
|
||||
}()
|
||||
|
||||
next.ServeHTTP(ww, r)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package server
|
||||
|
||||
import "github.com/go-chi/chi/v5"
|
||||
|
||||
type Controller interface {
|
||||
Router(r chi.Router)
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package server
|
||||
|
||||
import "golang.org/x/exp/slog"
|
||||
|
||||
type Options struct {
|
||||
ListenAddr string
|
||||
ListenPort int
|
||||
Logger *slog.Logger
|
||||
}
|
||||
|
||||
func DefaultOptions() *Options {
|
||||
return &Options{
|
||||
ListenAddr: "127.0.0.1",
|
||||
ListenPort: 8080,
|
||||
Logger: slog.Default(),
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Options) WithListenAddr(addr string) *Options {
|
||||
o.ListenAddr = addr
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithListenPort(port int) *Options {
|
||||
o.ListenPort = port
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithLogger(logger *slog.Logger) *Options {
|
||||
o.Logger = logger
|
||||
return o
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
"go.fifitido.net/ytdl-web/pkg/middlewarex"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type Server interface {
|
||||
MountController(path string, controller Controller)
|
||||
ListenAndServe() error
|
||||
}
|
||||
|
||||
type DefaultServer struct {
|
||||
r chi.Router
|
||||
opts *Options
|
||||
}
|
||||
|
||||
var _ Server = (*DefaultServer)(nil)
|
||||
|
||||
func New(options ...*Options) *DefaultServer {
|
||||
var opts *Options
|
||||
if len(options) > 0 {
|
||||
opts = options[0]
|
||||
} else {
|
||||
opts = DefaultOptions()
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middlewarex.SlogRequestLogger(opts.Logger))
|
||||
r.Use(middleware.Recoverer)
|
||||
|
||||
return &DefaultServer{
|
||||
r: r,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DefaultServer) MountController(path string, controller Controller) {
|
||||
s.r.Route(path, controller.Router)
|
||||
}
|
||||
|
||||
func (s *DefaultServer) ListenAndServe() error {
|
||||
listenAddr := fmt.Sprintf("%s:%d", s.opts.ListenAddr, s.opts.ListenPort)
|
||||
s.opts.Logger.Info("Starting HTTP server", slog.String("addr", s.opts.ListenAddr), slog.Int("port", s.opts.ListenPort))
|
||||
return http.ListenAndServe(listenAddr, s.r)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package view
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Data map[string]interface{}
|
||||
|
||||
type Engine interface {
|
||||
Load() error
|
||||
Render(w http.ResponseWriter, view string, data Data, layout ...string)
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go.fifitido.net/ytdl-web/pkg/view"
|
||||
)
|
||||
|
||||
type Engine struct {
|
||||
fs embed.FS
|
||||
tpl *template.Template
|
||||
opts *Options
|
||||
|
||||
loadOnce sync.Once
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
var _ view.Engine = (*Engine)(nil)
|
||||
|
||||
func New(fs embed.FS, options ...*Options) *Engine {
|
||||
var opts *Options
|
||||
if len(options) > 0 && options[0] != nil {
|
||||
opts = options[0]
|
||||
} else {
|
||||
opts = DefaultOptions()
|
||||
}
|
||||
|
||||
tpl := template.New("/")
|
||||
tpl.Delims(opts.LeftDelim, opts.RightDelim)
|
||||
tpl.Funcs(opts.FuncMap)
|
||||
|
||||
return &Engine{
|
||||
fs: fs,
|
||||
tpl: tpl,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Engine) Load() error {
|
||||
var err error
|
||||
e.loadOnce.Do(func() {
|
||||
err = e.doLoad()
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Engine) doLoad() error {
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
return fs.WalkDir(e.fs, ".", func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d == nil || d.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(path) < len(e.opts.Extension) || path[len(path)-len(e.opts.Extension):] != e.opts.Extension {
|
||||
return nil
|
||||
}
|
||||
|
||||
rel, err := filepath.Rel(e.opts.BaseDir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
name := filepath.ToSlash(rel)
|
||||
name = strings.TrimSuffix(name, e.opts.Extension)
|
||||
|
||||
buf, err := e.fs.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = e.tpl.New(name).Parse(string(buf))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (e *Engine) Render(w http.ResponseWriter, view string, data view.Data, layout ...string) {
|
||||
tmpl := e.tpl.Lookup(view)
|
||||
if tmpl == nil {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if len(layout) > 0 && layout[0] != "" {
|
||||
lay := e.tpl.Lookup(layout[0])
|
||||
if lay == nil {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
e.mu.Lock()
|
||||
defer e.mu.Unlock()
|
||||
|
||||
lay.Funcs(map[string]interface{}{
|
||||
"yield": func() error {
|
||||
return tmpl.Execute(w, data)
|
||||
},
|
||||
})
|
||||
|
||||
if err := lay.Execute(w, data); err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err := tmpl.Execute(w, data); err != nil {
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package html
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
LeftDelim string
|
||||
RightDelim string
|
||||
Extension string
|
||||
BaseDir string
|
||||
FuncMap template.FuncMap
|
||||
}
|
||||
|
||||
func DefaultOptions() *Options {
|
||||
return &Options{
|
||||
LeftDelim: "{{",
|
||||
RightDelim: "}}",
|
||||
Extension: ".html",
|
||||
BaseDir: "/",
|
||||
FuncMap: template.FuncMap{
|
||||
"yield": func() error { return fmt.Errorf("yield called outside of a layout") },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Options) WithDelimiters(left, right string) *Options {
|
||||
o.LeftDelim = left
|
||||
o.RightDelim = right
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithExtension(ext string) *Options {
|
||||
o.Extension = ext
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithBaseDir(dir string) *Options {
|
||||
o.BaseDir = dir
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithFunction(name string, fn interface{}) *Options {
|
||||
o.FuncMap[name] = fn
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Options) WithFunctions(funcs template.FuncMap) *Options {
|
||||
for k, v := range funcs {
|
||||
o.FuncMap[k] = v
|
||||
}
|
||||
return o
|
||||
}
|
|
@ -5,7 +5,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||
)
|
||||
|
||||
type MetadataCache interface {
|
|
@ -0,0 +1,19 @@
|
|||
package ytdl
|
||||
|
||||
type Error struct {
|
||||
stdout string
|
||||
stderr string
|
||||
child error
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return e.child.Error()
|
||||
}
|
||||
|
||||
func (e *Error) Stdout() string {
|
||||
return e.stdout
|
||||
}
|
||||
|
||||
func (e *Error) Stderr() string {
|
||||
return e.stderr
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
package ytdl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"go.fifitido.net/ytdl-web/config"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/cache"
|
||||
"go.fifitido.net/ytdl-web/pkg/ytdl/metadata"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type Ytdl interface {
|
||||
GetMetadata(url string) (*metadata.Metadata, error)
|
||||
Download(w io.Writer, url, format string, index int) error
|
||||
Version() string
|
||||
}
|
||||
|
||||
type ytdlImpl struct {
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
cache cache.MetadataCache
|
||||
version string
|
||||
}
|
||||
|
||||
func NewYtdl(cfg *config.Config, logger *slog.Logger, cache cache.MetadataCache) Ytdl {
|
||||
cmd := exec.Command(
|
||||
cfg.Ytdlp.BinaryPath,
|
||||
"--version",
|
||||
)
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
_ = cmd.Run()
|
||||
|
||||
return &ytdlImpl{
|
||||
cfg: cfg,
|
||||
logger: logger.With(slog.String("module", "ytdl")),
|
||||
cache: cache,
|
||||
version: strings.TrimSpace(out.String()),
|
||||
}
|
||||
}
|
||||
|
||||
func buildBrowserCookieString(browser, keyring, profile, container string) string {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(browser)
|
||||
|
||||
if keyring != "" {
|
||||
sb.WriteByte('+')
|
||||
sb.WriteString(keyring)
|
||||
}
|
||||
|
||||
if profile != "" {
|
||||
sb.WriteByte(':')
|
||||
sb.WriteString(profile)
|
||||
}
|
||||
|
||||
if container != "" {
|
||||
sb.WriteByte(':')
|
||||
sb.WriteByte(':')
|
||||
sb.WriteString(container)
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (y *ytdlImpl) appendCookieArgs(args []string) []string {
|
||||
if y.cfg.Cookies.Enabled {
|
||||
if y.cfg.Cookies.FromBrowser.Browser != "" {
|
||||
args = append(args, "--cookies-from-browser", buildBrowserCookieString(
|
||||
y.cfg.Cookies.FromBrowser.Browser,
|
||||
y.cfg.Cookies.FromBrowser.Keyring,
|
||||
y.cfg.Cookies.FromBrowser.Profile,
|
||||
y.cfg.Cookies.FromBrowser.Container,
|
||||
))
|
||||
} else {
|
||||
args = append(args, "--cookies", y.cfg.Cookies.FilePath)
|
||||
}
|
||||
}
|
||||
|
||||
return args
|
||||
}
|
||||
|
||||
func (y *ytdlImpl) Version() string {
|
||||
return y.version
|
||||
}
|
||||
|
||||
// GetMetadata implements Ytdl
|
||||
func (y *ytdlImpl) GetMetadata(url string) (*metadata.Metadata, error) {
|
||||
meta, err := y.cache.Get(url)
|
||||
if err == nil {
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
args := []string{
|
||||
url,
|
||||
"--dump-single-json",
|
||||
}
|
||||
|
||||
args = y.appendCookieArgs(args)
|
||||
|
||||
cmd := exec.Command(y.cfg.Ytdlp.BinaryPath, args...)
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
attrs := []any{
|
||||
slog.String("url", url),
|
||||
slog.String("error", err.Error()),
|
||||
}
|
||||
|
||||
y.logger.Error("failed to get metadata", attrs...)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
meta = &metadata.Metadata{}
|
||||
if err := json.Unmarshal(out, meta); err != nil {
|
||||
y.logger.Error("failed to unmarshal metadata", slog.String("url", url), slog.String("error", err.Error()))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := y.cache.Set(url, meta, y.cfg.Cache.TTL); err != nil {
|
||||
y.logger.Warn("failed to cache metadata", slog.String("url", url), slog.String("error", err.Error()))
|
||||
}
|
||||
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
// Download implements Ytdl
|
||||
func (y *ytdlImpl) Download(w io.Writer, url, format string, index int) error {
|
||||
args := []string{
|
||||
url,
|
||||
"--format", format,
|
||||
"--output", "-",
|
||||
}
|
||||
|
||||
if index >= 0 {
|
||||
args = append(args, "--playlist-ites", fmt.Sprint(index+1))
|
||||
}
|
||||
|
||||
args = y.appendCookieArgs(args)
|
||||
|
||||
metadata, err := y.cache.Get(url)
|
||||
if err == nil {
|
||||
args = append(args, "--load-info-json", "-")
|
||||
}
|
||||
|
||||
cmd := exec.Command(y.cfg.Ytdlp.BinaryPath, args...)
|
||||
cmd.Stdout = w
|
||||
|
||||
if err == nil {
|
||||
json, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmd.Stdin = bytes.NewReader(json)
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
y.logger.Error("failed to download", slog.String("url", url), slog.String("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"github.com/samber/lo"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
)
|
||||
|
||||
type Video struct {
|
||||
Meta *metadata.Metadata
|
||||
Formats []metadata.Format
|
||||
}
|
||||
|
||||
func GetVideos(meta *metadata.Metadata) []Video {
|
||||
if meta.IsPlaylist() {
|
||||
return lo.Map(meta.Entries, func(video metadata.Metadata, _ int) Video {
|
||||
return GetVideos(&video)[0]
|
||||
})
|
||||
}
|
||||
|
||||
formats := lo.Filter(meta.Formats, func(item metadata.Format, _ int) bool {
|
||||
return item.ACodec != "none" && item.VCodec != "none" && item.Protocol != "m3u8_native"
|
||||
})
|
||||
|
||||
for i, j := 0, len(formats)-1; i < j; i, j = i+1, j-1 {
|
||||
formats[i], formats[j] = formats[j], formats[i]
|
||||
}
|
||||
|
||||
return []Video{
|
||||
{
|
||||
Meta: meta,
|
||||
Formats: formats,
|
||||
},
|
||||
}
|
||||
}
|
122
web/routes.go
122
web/routes.go
|
@ -1,122 +0,0 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/sujit-baniya/flash"
|
||||
"go.fifitido.net/ytdl-web/version"
|
||||
"go.fifitido.net/ytdl-web/ytdl"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type routes struct {
|
||||
ytdl ytdl.Ytdl
|
||||
}
|
||||
|
||||
func (r *routes) Register(app *fiber.App) {
|
||||
app.Get("/", r.IndexHandler)
|
||||
app.Get("/download", r.DownloadHandler)
|
||||
app.Head("/download/proxy", r.DownloadProxyHandler)
|
||||
app.Get("/download/proxy", r.DownloadProxyHandler)
|
||||
}
|
||||
|
||||
func (r *routes) IndexHandler(c *fiber.Ctx) error {
|
||||
return c.Render("views/index", fiber.Map{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Flash": flash.Get(c),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"YtdlpVersion": ytdl.GetVersion(),
|
||||
}, "views/layouts/main")
|
||||
}
|
||||
|
||||
func (r *routes) DownloadHandler(c *fiber.Ctx) error {
|
||||
urlBytes, err := url.QueryUnescape(c.Query("url"))
|
||||
if err != nil {
|
||||
return flash.WithError(c, fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid URL",
|
||||
}).Redirect("/")
|
||||
}
|
||||
url := string(urlBytes)
|
||||
if len(url) < 1 {
|
||||
return flash.WithError(c, fiber.Map{
|
||||
"error": true,
|
||||
"message": "Invalid URL",
|
||||
}).Redirect("/")
|
||||
}
|
||||
|
||||
meta, err := r.ytdl.GetMetadata(url)
|
||||
if err != nil {
|
||||
return flash.WithError(c, fiber.Map{
|
||||
"error": true,
|
||||
"message": "Could not find a video at that url, maybe try again?",
|
||||
}).Redirect("/")
|
||||
}
|
||||
|
||||
return c.Render("views/download", fiber.Map{
|
||||
"BasePath": viper.GetString("base_path"),
|
||||
"Url": url,
|
||||
"Meta": meta,
|
||||
"Videos": GetVideos(meta),
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"YtdlpVersion": ytdl.GetVersion(),
|
||||
}, "views/layouts/main")
|
||||
}
|
||||
|
||||
func (r *routes) DownloadProxyHandler(c *fiber.Ctx) error {
|
||||
urlBytes, err := url.QueryUnescape(c.Query("url"))
|
||||
if err != nil {
|
||||
slog.Error("Failed to decode url param", slog.String("error", err.Error()))
|
||||
return fiber.ErrBadRequest
|
||||
}
|
||||
url := string(urlBytes)
|
||||
if len(url) < 1 {
|
||||
return fiber.ErrBadRequest
|
||||
}
|
||||
|
||||
formatId := c.Query("format")
|
||||
if len(formatId) < 1 {
|
||||
return fiber.ErrBadRequest
|
||||
}
|
||||
|
||||
meta, err := r.ytdl.GetMetadata(url)
|
||||
if err != nil {
|
||||
slog.Error("Failed to get metadata", slog.String("error", err.Error()))
|
||||
return fiber.ErrInternalServerError
|
||||
}
|
||||
|
||||
videos := GetVideos(meta)
|
||||
index := c.QueryInt("index")
|
||||
|
||||
if index < 0 || index >= len(videos) {
|
||||
return fiber.ErrBadRequest
|
||||
}
|
||||
|
||||
video := videos[index]
|
||||
format, ok := lo.Find(video.Formats, func(format metadata.Format) bool {
|
||||
return format.FormatID == formatId
|
||||
})
|
||||
if !ok {
|
||||
return fiber.ErrBadRequest
|
||||
}
|
||||
|
||||
c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s-%s.%s\"", meta.ID, format.Resolution, format.Ext))
|
||||
if format.Filesize != nil {
|
||||
c.Set("Content-Length", fmt.Sprint(*format.Filesize))
|
||||
} else if format.FilesizeApprox != nil {
|
||||
c.Set("Content-Length", fmt.Sprint(*format.FilesizeApprox))
|
||||
}
|
||||
|
||||
if len(videos) == 1 {
|
||||
index = -1
|
||||
}
|
||||
|
||||
return r.ytdl.Download(c.Response().BodyWriter(), url, format.FormatID, index)
|
||||
}
|
50
web/serve.go
50
web/serve.go
|
@ -1,50 +0,0 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
slogfiber "github.com/samber/slog-fiber"
|
||||
"go.fifitido.net/ytdl-web/config"
|
||||
"go.fifitido.net/ytdl-web/utils"
|
||||
"go.fifitido.net/ytdl-web/ytdl"
|
||||
"go.fifitido.net/ytdl-web/ytdl/cache"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
func Serve(cfg *config.Config) error {
|
||||
engine := ViewsEngine()
|
||||
app := fiber.New(fiber.Config{
|
||||
Views: engine,
|
||||
EnableTrustedProxyCheck: true,
|
||||
TrustedProxies: cfg.HTTP.TrustedProxies,
|
||||
DisableStartupMessage: true,
|
||||
})
|
||||
|
||||
logger := slog.With("module", "web")
|
||||
app.Use(slogfiber.New(logger))
|
||||
|
||||
db, err := badger.Open(
|
||||
badger.
|
||||
DefaultOptions(cfg.Cache.DirPath).
|
||||
WithLogger(utils.NewBadgerLogger(slog.With("module", "badger"))),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
cache := cache.NewDefaultMetadataCache(db)
|
||||
|
||||
routes := &routes{
|
||||
ytdl: ytdl.NewYtdl(cfg, slog.Default(), cache),
|
||||
}
|
||||
routes.Register(app)
|
||||
|
||||
listenAddr := fmt.Sprintf("%s:%d", cfg.HTTP.Listen, cfg.HTTP.Port)
|
||||
|
||||
logger.Info("Starting HTTP server", slog.String("host", cfg.HTTP.Listen), slog.Int("port", cfg.HTTP.Port))
|
||||
|
||||
return app.Listen(listenAddr)
|
||||
}
|
52
web/views.go
52
web/views.go
|
@ -1,52 +0,0 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"html/template"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/gofiber/template/html"
|
||||
"github.com/htfy96/reformism"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
)
|
||||
|
||||
//go:embed views/*
|
||||
var viewsfs embed.FS
|
||||
|
||||
func ViewsEngine() *html.Engine {
|
||||
engine := html.NewFileSystem(http.FS(viewsfs), ".html")
|
||||
engine.AddFunc(
|
||||
"unsafe", func(s string) template.HTML {
|
||||
return template.HTML(s)
|
||||
},
|
||||
)
|
||||
engine.AddFunc(
|
||||
"queryEscape", func(s string) string {
|
||||
return url.QueryEscape(s)
|
||||
},
|
||||
)
|
||||
engine.AddFunc(
|
||||
"jsonMarshal", func(s any) (string, error) {
|
||||
j, err := json.MarshalIndent(s, "", " ")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(j), nil
|
||||
},
|
||||
)
|
||||
engine.AddFunc(
|
||||
"downloadContext", func(meta metadata.Metadata, url, basePath string, format metadata.Format) map[string]any {
|
||||
return map[string]any{
|
||||
"Meta": meta,
|
||||
"Url": url,
|
||||
"BasePath": basePath,
|
||||
"Format": format,
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
engine.AddFuncMap(reformism.FuncsHTML)
|
||||
return engine
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<div class="d-flex flex-column align-items-center">
|
||||
<h1>Download Video</h1>
|
||||
<h2 class="fs-4 text-muted text-center">{{.Meta.Title}}</h2>
|
||||
<p style="font-size: 0.85rem">{{.Url}}</p>
|
||||
<a href="{{.BasePath}}/" class="btn btn-secondary btn-sm mt-3" style="width: 30rem; max-width: 100%">
|
||||
Download Another Video
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{{$root := .}}
|
||||
|
||||
{{range $vidIndex, $video := .Videos}}
|
||||
{{if not (eq $vidIndex 0)}}
|
||||
<hr class="mt-5" />
|
||||
{{end}}
|
||||
<div class="d-flex flex-column flex-lg-row justify-content-center gap-5 mt-5">
|
||||
<div class="d-flex justify-content-center">
|
||||
<img src="{{.Meta.Thumbnail}}" alt="{{.Meta.Title}}" style="max-height: 25rem; max-width: 100%; margin: 0 auto;" />
|
||||
</div>
|
||||
<div class="downloads flex-lg-grow-1">
|
||||
{{range $index, $format := $video.Formats}}
|
||||
<div style="font-size: smaller">{{$format.Format}}</div>
|
||||
<div class="flex-grow-1 d-flex gap-3">
|
||||
<a class="btn btn-primary flex-grow-1" download="{{$root.Meta.ID}}-{{$format.Resolution}}.{{$format.Ext}}" P
|
||||
href="{{$format.Url}}">
|
||||
Download (direct)
|
||||
</a>
|
||||
<a class="btn btn-primary flex-grow-1" download="{{$root.Meta.ID}}-{{$format.Resolution}}.{{$format.Ext}}"
|
||||
href="{{$root.BasePath}}/download/proxy?url={{queryEscape $root.Url}}&format={{$format.FormatID}}&index={{$vidIndex}}">
|
||||
Download (proxied)
|
||||
</a>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
|
@ -1,20 +0,0 @@
|
|||
<footer class="footer mt-auto py-3 bg-body-tertiary" style="font-size: 0.95rem">
|
||||
<div class="container">
|
||||
<div class="row gap-2 gap-md-0">
|
||||
<div class="d-flex gap-4 col-md justify-content-center">
|
||||
<div class="d-flex gap-1 align-items-baseline">
|
||||
Version:
|
||||
<span class="text-muted">{{.Version}}</span>
|
||||
<span class="text-muted text-nowrap" style="font-size: smaller;">(Build: {{.Build}})</span>
|
||||
</div>
|
||||
<div class="d-flex gap-1 align-items-baseline text-nowrap">
|
||||
yt-dlp version: <span class="text-muted">{{.YtdlpVersion}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-2 col-md justify-content-center">
|
||||
<a href="https://git.fifitido.net/apps/ytdl-web">Git Repository</a>
|
||||
<span class="text-muted">© 2023 FiFiTiDo</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
|
@ -1,52 +0,0 @@
|
|||
package ytdl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"os/exec"
|
||||
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
)
|
||||
|
||||
func Exec(binary, url string, options ...Option) error {
|
||||
opts := Options{
|
||||
args: []string{url},
|
||||
stdin: nil,
|
||||
stdout: nil,
|
||||
stderr: nil,
|
||||
output: nil,
|
||||
}
|
||||
for _, opt := range options {
|
||||
if err := opt(&opts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(binary, opts.args...)
|
||||
|
||||
if opts.stdin != nil {
|
||||
cmd.Stdin = opts.stdin
|
||||
}
|
||||
|
||||
if opts.stdout != nil {
|
||||
cmd.Stdout = opts.stdout
|
||||
}
|
||||
|
||||
if opts.stderr != nil {
|
||||
cmd.Stderr = opts.stderr
|
||||
}
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf, bufOk := opts.stdout.(*bytes.Buffer)
|
||||
meta, metaOk := opts.output.(*metadata.Metadata)
|
||||
if bufOk && metaOk {
|
||||
if err := json.Unmarshal(buf.Bytes(), meta); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
109
ytdl/cmdopts.go
109
ytdl/cmdopts.go
|
@ -1,109 +0,0 @@
|
|||
package ytdl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"go.fifitido.net/ytdl-web/utils"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
args []string
|
||||
stdin io.Reader
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
output interface{}
|
||||
}
|
||||
|
||||
type Option func(*Options) error
|
||||
|
||||
func WithFormat(format string) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--format", format)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithCookieFile(cookieFile string) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--cookies", cookieFile)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithDumpJson(meta *metadata.Metadata) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--dump-single-json")
|
||||
opts.stdout = new(bytes.Buffer)
|
||||
opts.output = meta
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithLoadJson(metadata *metadata.Metadata) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--load-info-json", "-")
|
||||
|
||||
json, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts.stdin = bytes.NewBuffer(json)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithBrowserCookies(browser, keyring, profile, container string) Option {
|
||||
return func(opts *Options) error {
|
||||
var sb strings.Builder
|
||||
sb.WriteString(browser)
|
||||
|
||||
if keyring != "" {
|
||||
sb.WriteByte('+')
|
||||
sb.WriteString(keyring)
|
||||
}
|
||||
|
||||
if profile != "" {
|
||||
sb.WriteByte(':')
|
||||
sb.WriteString(profile)
|
||||
}
|
||||
|
||||
if container != "" {
|
||||
sb.WriteByte(':')
|
||||
sb.WriteByte(':')
|
||||
sb.WriteString(container)
|
||||
}
|
||||
|
||||
opts.args = append(opts.args, "--cookies-from-browser", sb.String())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithStreamOutput(output io.Writer) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--output", "-")
|
||||
opts.stdout = output
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithDebug() Option {
|
||||
return func(opts *Options) error {
|
||||
opts.stdout = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
|
||||
opts.stderr = utils.LoggerWriter(slog.With("module", "ytdl"), slog.LevelDebug)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func WithPlaylistIndex(index int) Option {
|
||||
return func(opts *Options) error {
|
||||
opts.args = append(opts.args, "--playlist-items", fmt.Sprint(index+1))
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
package ytdl
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
version string
|
||||
versionOnce sync.Once
|
||||
)
|
||||
|
||||
func GetVersion() string {
|
||||
var err error
|
||||
versionOnce.Do(func() {
|
||||
cmd := exec.Command(
|
||||
viper.GetString("ytdlp_path"),
|
||||
"--version",
|
||||
)
|
||||
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
version = strings.TrimSpace(out.String())
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "Error getting version"
|
||||
}
|
||||
|
||||
return version
|
||||
}
|
101
ytdl/ytdl.go
101
ytdl/ytdl.go
|
@ -1,101 +0,0 @@
|
|||
package ytdl
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"go.fifitido.net/ytdl-web/config"
|
||||
"go.fifitido.net/ytdl-web/ytdl/cache"
|
||||
"go.fifitido.net/ytdl-web/ytdl/metadata"
|
||||
"golang.org/x/exp/slog"
|
||||
)
|
||||
|
||||
type Ytdl interface {
|
||||
GetMetadata(url string) (*metadata.Metadata, error)
|
||||
Download(w io.Writer, url, format string, index int) error
|
||||
}
|
||||
|
||||
type ytdlImpl struct {
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
cache cache.MetadataCache
|
||||
}
|
||||
|
||||
func NewYtdl(cfg *config.Config, logger *slog.Logger, cache cache.MetadataCache) Ytdl {
|
||||
return &ytdlImpl{
|
||||
cfg: cfg,
|
||||
logger: logger.With(slog.String("module", "ytdl")),
|
||||
cache: cache,
|
||||
}
|
||||
}
|
||||
|
||||
func (y *ytdlImpl) baseOptions(url string) []Option {
|
||||
options := []Option{}
|
||||
|
||||
metadata, err := y.cache.Get(url)
|
||||
if err == nil {
|
||||
options = append(options, WithLoadJson(metadata))
|
||||
}
|
||||
|
||||
if y.cfg.Cookies.Enabled {
|
||||
if y.cfg.Cookies.FromBrowser.Browser != "" {
|
||||
options = append(options, WithBrowserCookies(
|
||||
y.cfg.Cookies.FromBrowser.Browser,
|
||||
y.cfg.Cookies.FromBrowser.Keyring,
|
||||
y.cfg.Cookies.FromBrowser.Profile,
|
||||
y.cfg.Cookies.FromBrowser.Container,
|
||||
))
|
||||
} else {
|
||||
options = append(options, WithCookieFile(y.cfg.Cookies.FilePath))
|
||||
}
|
||||
}
|
||||
|
||||
if y.cfg.IsDevelopment() {
|
||||
options = append(options, WithDebug())
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
// GetMetadata implements Ytdl
|
||||
func (y *ytdlImpl) GetMetadata(url string) (*metadata.Metadata, error) {
|
||||
meta, err := y.cache.Get(url)
|
||||
if err == nil {
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
meta = &metadata.Metadata{}
|
||||
options := append(
|
||||
y.baseOptions(url),
|
||||
WithDumpJson(meta),
|
||||
)
|
||||
|
||||
if err := Exec(y.cfg.BinaryPath, url, options...); err != nil {
|
||||
y.logger.Error("failed to get metadata", slog.String("url", url), slog.String("error", err.Error()))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := y.cache.Set(url, meta, y.cfg.Cache.TTL); err != nil {
|
||||
y.logger.Warn("failed to cache metadata", slog.String("url", url), slog.String("error", err.Error()))
|
||||
}
|
||||
|
||||
return meta, nil
|
||||
}
|
||||
|
||||
// Download implements Ytdl
|
||||
func (y *ytdlImpl) Download(w io.Writer, url, format string, index int) error {
|
||||
options := append(
|
||||
y.baseOptions(url),
|
||||
WithFormat(format),
|
||||
WithStreamOutput(w),
|
||||
)
|
||||
|
||||
if index >= 0 {
|
||||
options = append(options, WithPlaylistIndex(index))
|
||||
}
|
||||
|
||||
if err := Exec(y.cfg.BinaryPath, url, options...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue