diff --git a/.gitignore b/.gitignore
index 3da785e80..c8f3ae875 100644
--- a/.gitignore
+++ b/.gitignore
@@ -358,3 +358,13 @@ tencentScf/.env
# vs code
.vscode
+
+# krew
+krew/bilipro
+krew/cmd/kubectl-bilipro
+krew/kustomization.yaml
+bilipro
+kustomization.yaml
+
+# cookie config
+cookies.json
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fce9a6529..3b5b367b8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -63,5 +63,10 @@
- 合并PR(#309)新增lv6后开启白嫖模式的配置(多账号时可以实现不足lv6的继续投币,达到lv6的开始白嫖),感谢@cluom
- 优化青龙安装dotnet的脚本,改为使用官方`dotnet-install.sh`脚本安装(之前测试网络不通,后发现--no-cdn可以)
- 优化青龙的执行脚本,提取公共部分,并且在执行前会尝试安装一次dotnet,会清理一次缓存
-## 0.2.3
+## 0.3.0
- hotfix docker build error
+- 合并PR(#341),新增krew部署,感谢@chenliu1993
+- 合并PR(##348),更新文档,感谢@jexjws
+- 合并PR(#350),修改请求header错误的bug
+- 合并PR(#353),新增python扫码登录的feature(仅针对青龙),感谢@AFUL1991
+- Feature(#351):重构并新增了扫码登录功能,使之适用于各种部署平台
diff --git a/README.md b/README.md
index 3cb5d732f..3457bb5cf 100644
--- a/README.md
+++ b/README.md
@@ -40,15 +40,14 @@ BiliBiliTool
- [1. 如何使用](#1-如何使用)
- - [1.1. 第一步:获取BiliBili的 Cookie](#11-第一步获取bilibili的-cookie)
- - [1.2. 第二步:配置 Cookie 并运行 BiliBiliTool](#12-第二步配置-cookie-并运行-bilibilitool)
- - [1.2.1. 方式一:青龙运行(推荐)](#121-方式一青龙运行推荐)
- - [1.2.2. 方式二:Docker或Podman容器化运行](#122-方式二docker或podman容器化运行)
- - [1.2.3. 方式三:下载程序包到本地或服务器运行](#123-方式三下载程序包到本地或服务器运行)
- - [1.2.4. 方式四:腾讯云函数SCF](#124-方式四腾讯云函数scf)
- - [1.2.5. 方式五:~~GitHub Actions~~](#125-方式五github-actions)
- - [1.2.6. 方式六:Chart部署](#126-方式六chart部署)
- - [1.3. 消息推动(可选)](#13-消息推动可选)
+ - [1.1. 部署 BiliBiliTool](#11-部署-bilibilitool)
+ - [1.1.1. 方式一:青龙(推荐)](#111-方式一青龙推荐)
+ - [1.1.2. 方式二:Docker或Podman容器化运行](#112-方式二docker或podman容器化运行)
+ - [1.1.3. 方式三:下载程序包到本地或服务器运行](#113-方式三下载程序包到本地或服务器运行)
+ - [1.1.4. 方式四:腾讯云函数SCF](#114-方式四腾讯云函数scf)
+ - [1.1.5. 方式五:~~GitHub Actions~~](#115-方式五github-actions)
+ - [1.1.6. 方式六:Chart部署](#116-方式六chart部署)
+ - [1.2. 消息推送(可选)](#12-消息推送可选)
- [2. 功能任务说明](#2-功能任务说明)
- [3. 个性化自定义配置](#3-个性化自定义配置)
- [4. 多账号支持](#4-多账号支持)
@@ -82,105 +81,44 @@ _(如果图片挂了,请自己架梯子,没有的也可以先参考 [我
BiliBiliTool 实现自动完成任务的原理,是通过调用一系列开放的api实现的。
-**要使用 BiliBiliTool,我们只需要做两步:获取自己的 Cookie 作为配置,然后将其输入 BiliBiliTool 并运行即可。**
+**要使用 BiliBiliTool,很简单,按照下面教程部署完成,运行后扫码登录即可。**
-### 1.1. 第一步:获取BiliBili的 Cookie
+### 1.1. 部署 BiliBiliTool
-- 浏览器打开并登录 [BiliBili 网站](https://www.bilibili.com/)
-- 登录成功后,访问 `https://api.bilibili.com/x/web-interface/nav`,按 **F12** 打开"开发者工具",按 **F5** 刷新一下
-- 在"开发者工具"面板中,点击 **网络(Network)**,在左侧的请求列表中,找到名称为 `nav` 的接口,点击它
-- 依次查找 **Headers** ——> **RequestHeader** ——> **cookie**,可以看到很长一串以英文分号分隔的字符串,复制整个这个cookie字符串(不要使用右键复制,请使用 Ctrl+C 复制,部分浏览器右键可能会进行 UrlDecode ),保存它们到记事本,待会儿会用到。
+支持多种部署方式,以下选择任一适合自己的方式即可。
-![获取Cookie图示](docs/imgs/get-bilibili-web-cookie.jpg)
-
-
-### 1.2. 第二步:配置 Cookie 并运行 BiliBiliTool
-
-#### 1.2.1. 方式一:青龙运行(推荐)
+#### 1.1.1. 方式一:青龙(推荐)
[>>青龙部署教程](qinglong/README.md)
-#### 1.2.2. 方式二:Docker或Podman容器化运行
+#### 1.1.2. 方式二:Docker或Podman容器化运行
[>>Docker部署说明](docker/README.md)
[>>Podman部署说明](podman/README.md)
-#### 1.2.3. 方式三:下载程序包到本地或服务器运行
-
-如果是 DotNet 开发者,直接 Clone 源码,然后 VS 打开解决方案,配置 Cookie 后即可直接本地进行运行和调试。
-
-对于不是开发者的朋友,可以通过下载 Release 包到本地或任意服务器运行,步骤如下。
-
-
-Ⅰ. **下载应用文件**
-
-点击 [BiliBiliTool/release](https://github.com/RayWangQvQ/BiliBiliToolPro/releases),下载已发布的最新版本。
-
-* 如果本地已安装 `.NET 6.0` 环境:
-
-请下载 `net-dependent.zip` 文件,本文件依赖本地运行库(runtime-dependent),所以文件包非常小(不到1M)。
-
-P.S.这里的运行环境指的是 `.NET Runtime 6.0.0` ,安装方法可详见 [常见问题](docs/questions.md) 中的 **本地或服务器如何安装.net环境**
-
-* 如果不希望安装或不知如何安装.net运行环境:
-
-请根据操作系统下载对应的 zip 文件,此文件已自包含(self-contained)运行环境,但相较不包含运行时的文件略大(20M 左右,Github 服务器在国外,下载可能比较慢)。
-
-如,Windows系统请下载 `win-x86-x64.zip` ,其他以此类推。
-
-
-Ⅱ. **解压并填写配置**
-
-下载并解压后,找到 appsettings.json 文件,使用记事本编辑,将之前获取到的 Cookie 字符串填入指定位置,保存后关闭:
-
-![配置文件图示](docs/imgs/appsettings-cookie.png)
-
-Ⅲ. **运行**
-
-* Windows 系统
-
-对于已安装.net环境,且使用的是依赖包,可在当前目录下执行命令:`dotnet Ray.BiliBiliTool.Console.dll`,或者直接双击运行名称为 start.bat 的批处理文件,均可运行。
-
-对于使用自包含运行环境版本的,可直接双击运行名称为 Ray.BiliBiliTool.Console.exe 的可执行文件。
-
-* Linux 系统
-
-对于已安装.net环境,且使用的是依赖包,同上,可在终端中执行命令:`dotnet Ray.BiliBiliTool.Console.dll`
-
-对于使用独立包的,可在终端中执行命令:
-
-```
-chmod +x ./Ray.BiliBiliTool.Console
-Ray.BiliBiliTool.Console
-```
-
-其他系统依此类推,运行结果图示如下:
-
-![运行图示](docs/imgs/run-exe.png)
-
-除了修改配置文件,也可以通过添加环境变量或在启动命令后附加参数来实现配置,详细方法可参考下面的**配置说明**章节。
+#### 1.1.3. 方式三:下载程序包到本地或服务器运行
-
+[>>本地部署说明](docs/runInLocal.md)
-#### 1.2.4. 方式四:腾讯云函数SCF
+#### 1.1.4. 方式四:腾讯云函数SCF
当前腾讯云函数已改为收费模式,不推荐。
[>>腾讯云函数部署说明](tencentScf/README.md)
-#### 1.2.5. 方式五:~~GitHub Actions~~
+#### 1.1.5. 方式五:~~GitHub Actions~~
暂时删掉该方式避避风头。
**建议所有使用该方式运行的朋友,暂时先替换其他运行方式,避免造成不必要的损失。**
-#### 1.2.6. 方式六:Chart部署
+#### 1.1.6. 方式六:Chart部署
[>>Chart部署说明](helm/README.md)
-### 1.3. 消息推动(可选)
+### 1.2. 消息推送(可选)
如果配置了推送,执行成功后,指定的接收端会收到推送消息,推送效果如下所示:
diff --git a/common.props b/common.props
index 8180db785..1ac4a8905 100644
--- a/common.props
+++ b/common.props
@@ -1,7 +1,7 @@
Ray
- 0.2.3
+ 0.3.0
$(NoWarn);CS1591;CS0436
diff --git a/docker/README.md b/docker/README.md
index 120cc892a..140c2805c 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -6,14 +6,14 @@
- [1.2. 须知](#12-须知)
- [2. 方式一:Docker Compose(推荐)](#2-方式一docker-compose推荐)
- [2.1. 启动](#21-启动)
- - [2.2. 修改bili下的docker-compose.yml,填入cookie](#22-修改bili下的docker-composeyml填入cookie)
- - [2.3. 其他命令参考](#23-其他命令参考)
+ - [2.2. 其他命令参考](#22-其他命令参考)
- [3. 方式二:Docker指令](#3-方式二docker指令)
- [3.1. Docker启动](#31-docker启动)
- [3.2. 其他指令参考](#32-其他指令参考)
- [3.3. 使用Watchtower更新容器](#33-使用watchtower更新容器)
-- [4. 自己构建镜像(非必须)](#4-自己构建镜像非必须)
-- [5. 其他](#5-其他)
+- [4. 登录](#4-登录)
+- [5. 自己构建镜像(非必须)](#5-自己构建镜像非必须)
+- [6. 其他](#6-其他)
## 1. 前期工作
@@ -52,6 +52,7 @@ docker pull zai7lou/bilibili_tool_pro
# 下载
wget https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/src/Ray.BiliBiliTool.Console/appsettings.json
+wget https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/docker/sample/cookies.json
wget https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/docker/sample/docker-compose.yml
# 启动
@@ -61,21 +62,16 @@ docker compose up -d
docker logs -f bili
```
-### 2.2. 修改bili下的docker-compose.yml,填入cookie
-
-根据 docker-compose.yaml 里面的注释编辑所需配置,`environment` 下可以通过环境变量自由添加自定义配置,其中Cookie是必填的,所以请至少填入Cookie并保存。
-
-保存后,重新运行下`docker compose up -d`
-
最终文件结构如下:
```
bili
├── appsettings.json
+├── cookies.json
└── docker-compose.yml
```
-### 2.3. 其他命令参考
+### 2.2. 其他命令参考
```
# 启动 docker-compose
@@ -103,7 +99,6 @@ docker compose pull && docker compose up -d
docker pull zai7lou/bilibili_tool_pro
docker run -d --name="bili" \
-v /bili/Logs:/app/Logs \
- -e Ray_BiliBiliCookies__1="cookie" \
-e Ray_DailyTaskConfig__Cron="0 15 * * *" \
-e Ray_LiveLotteryTaskConfig__Cron="0 22 * * *" \
-e Ray_UnfollowBatchedTaskConfig__Cron="0 6 1 * *" \
@@ -125,6 +120,9 @@ docker start bili
# 停止容器
docker stop bili
+# 重启容器
+docker restart bili
+
# 删除容器
docker rm bili
@@ -141,7 +139,15 @@ docker run --rm \
bili
```
-## 4. 自己构建镜像(非必须)
+## 4. 登录
+
+在宿主机运行`docker exec -it bili bash -c "dotnet Ray.BiliBiliTool.Console.dll --runTasks=Login"`
+
+扫码进行登录。
+
+![login](../docs/imgs/docker-login.png)
+
+## 5. 自己构建镜像(非必须)
目前我提供和维护的镜像:`[zai7lou/bilibili_tool_pro](https://hub.docker.com/repository/docker/zai7lou/bilibili_tool_pro)`;
@@ -153,7 +159,7 @@ docker run --rm \
`TARGET_NAME`为镜像名称和版本,可以自己起个名字
-## 5. 其他
+## 6. 其他
代码编译和发布环境: mcr.microsoft.com/dotnet/sdk:6.0
diff --git a/docker/sample/docker-compose.yml b/docker/sample/docker-compose.yml
index e87fd75f8..bca5efa0e 100644
--- a/docker/sample/docker-compose.yml
+++ b/docker/sample/docker-compose.yml
@@ -8,15 +8,12 @@ services:
volumes:
- ./Logs:/app/Logs
- ./appsettings.json:/app/appsettings.json
+ - ./cookies.json:/app/cookies.json
tty: true
environment:
- ASPNETCORE_ENVIRONMENT=Production
- Ray_Security__IsSkipDailyTask=false
- # Cookie字符串(必填):
- - Ray_BiliBiliCookies__1=
- - Ray_BiliBiliCookies__2=
-
# 定时任务
- Ray_DailyTaskConfig__Cron=0 15 * * *
- Ray_LiveLotteryTaskConfig__Cron=0 22 * * *
diff --git a/docs/imgs/docker-login.png b/docs/imgs/docker-login.png
new file mode 100644
index 000000000..07d4d1f38
Binary files /dev/null and b/docs/imgs/docker-login.png differ
diff --git a/docs/imgs/qinglong-login.png b/docs/imgs/qinglong-login.png
new file mode 100644
index 000000000..c20d25376
Binary files /dev/null and b/docs/imgs/qinglong-login.png differ
diff --git a/docs/runInLocal.md b/docs/runInLocal.md
new file mode 100644
index 000000000..74d56533a
--- /dev/null
+++ b/docs/runInLocal.md
@@ -0,0 +1,58 @@
+# 下载程序包到本地或服务器运行
+
+
+
+- [1. 下载应用文件](#1-下载应用文件)
+- [2. 运行](#2-运行)
+
+
+
+如果是 DotNet 开发者,直接 Clone 源码,然后 VS 打开解决方案,配置 Cookie 后即可直接本地进行运行和调试。
+
+对于不是开发者的朋友,可以通过下载 Release 包到本地或任意服务器运行,步骤如下。
+
+
+## 1. 下载应用文件
+
+点击 [BiliBiliTool/release](https://github.com/RayWangQvQ/BiliBiliToolPro/releases),下载已发布的最新版本。
+
+* 如果本地已安装 `.NET 6.0` 环境:
+
+请下载 `net-dependent.zip` 文件,本文件依赖本地运行库(runtime-dependent),所以文件包非常小(不到1M)。
+
+P.S.这里的运行环境指的是 `.NET Runtime 6.0.0` ,安装方法可详见 [常见问题](docs/questions.md) 中的 **本地或服务器如何安装.net环境**
+
+* 如果不希望安装或不知如何安装.net运行环境:
+
+请根据操作系统下载对应的 zip 文件,此文件已自包含(self-contained)运行环境,但相较不包含运行时的文件略大(20M 左右,Github 服务器在国外,下载可能比较慢)。
+
+如,Windows系统请下载 `win-x86-x64.zip` ,其他以此类推。
+
+## 2. 运行
+
+下载并解压zip文件。
+
+* Windows 系统
+
+对于已安装.net环境,且使用的是依赖包,可在当前目录下执行命令:`dotnet Ray.BiliBiliTool.Console.dll --runTasks=Login`,或者直接双击运行名称为 start.bat 的批处理文件,均可运行。
+
+对于使用自包含运行环境版本的,可直接双击运行名称为 Ray.BiliBiliTool.Console.exe 的可执行文件。
+
+* Linux 系统
+
+对于已安装.net环境,且使用的是依赖包,同上,可在终端中执行命令:`dotnet Ray.BiliBiliTool.Console.dll --runTasks=Login`
+
+对于使用独立包的,可在终端中执行命令:
+
+```
+chmod +x ./Ray.BiliBiliTool.Console
+Ray.BiliBiliTool.Console
+```
+
+其他系统依此类推,运行结果图示如下:
+
+![运行图示](docs/imgs/run-exe.png)
+
+除了修改配置文件,也可以通过添加环境变量或在启动命令后附加参数来实现配置,详细方法可参考下面的**配置说明**章节。
+
+
diff --git a/krew/Makefile b/krew/Makefile
new file mode 100644
index 000000000..bd1bf7be1
--- /dev/null
+++ b/krew/Makefile
@@ -0,0 +1,34 @@
+.DEFAULT_GOAL:=help
+SHELL := /usr/bin/env bash
+
+ROOT_DIR := $(shell git rev-parse --show-toplevel)
+GOOS ?= $(shell go env GOOS)
+GOARCH ?= $(shell go env GOARCH)
+BIN_NAME ?= kubectl-bilipro
+KUBECTL_DIR ?= $(shell which kubectl | awk -F 'kubectl' '{printf "%s\n", $$1 }')
+
+
+
+GITCOMMIT ?= `git rev-parse HEAD`
+
+help: #### display help
+ @awk 'BEGIN {FS = ":.*## "; printf "\nTargets:\n"} /^[a-zA-Z_-]+:.*?#### / { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+ @awk 'BEGIN {FS = ":.* ## "; printf "\n \033[1;32mBuild targets\033[36m\033[0m\n \033[0;37mTargets for building and/or installing CLI plugins on the system.\n Append \"ENVS=\" to the end of these targets to limit the binaries built.\n e.g.: make build-all-tanzu-cli-plugins ENVS=linux-amd64 \n List available at https://github.com/golang/go/blob/master/src/go/build/syslist.go\033[36m\033[0m\n\n"} /^[a-zA-Z_-]+:.*? ## / { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
+##### GLOBAL
+
+.PHONY: deploy
+deploy: build install #### build + install
+
+
+.PHONY: build
+build: #### build the plugin
+ @go vet ./... && \
+ go fmt ./... && \
+ cd ${ROOT_DIR}/krew/cmd && \
+ GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -ldflags "-X github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd.Version=${GITCOMMIT}" -o $(BIN_NAME) kubectl-bilipro.go
+
+
+.PHONY: install
+install: #### install the plugin
+ @cd ${ROOT_DIR}/krew/cmd && \
+ sudo install ./$(BIN_NAME) ${KUBECTL_DIR}/$(BIN_NAME)
\ No newline at end of file
diff --git a/krew/README.md b/krew/README.md
new file mode 100644
index 000000000..af6acd696
--- /dev/null
+++ b/krew/README.md
@@ -0,0 +1,68 @@
+# BiliBiliPro Kubectl Plugin
+
+## Prerequisites
+
+- Kubernetes >= v1.23.0.
+- go >= v1.18
+- kubectl installed on your local machine, configured to an existing healthy Kubernetes cluster.
+- [krew](https://krew.sigs.k8s.io/docs/user-guide/setup/install/) plugin installed
+
+## Install Plugin
+
+Command: `cd ./krew && make deploy`
+The binary will be generated in cmd/ install it alonside the kubectl binary.
+
+For example: the kubectl is installed under `/usr/bin`, then put the bilibilipro plugin under `/usr/bin` too.
+
+## Plugin Commands
+
+### Deployment && Update
+
+Command: `kubectl bilipro init --config config.yaml`
+
+Creates Deployment with the needed environments.
+
+
+Optional Options:
+
+- `--image=zai7lou/bilibili_tool_pro:0.2.1`
+- `--namespace=bilipro`
+- `--image-pull-secret=`
+
+Required Options:
+
+- `--config=`
+
+The content of is a yaml array, please refer to the example config yaml under the krew directory.
+
+For example
+````yaml
+- name: Ray_BiliBiliCookies__2
+ value: "cookie"
+ # DailyTrigger - required
+- name: Ray_DailyTaskConfig__Cron
+ value: "11 11 * * *"
+````
+
+
+Suggestions: Deploy this workload in namespace other than default or kube-* namespace, because the delete logic should be improved
+
+
+### Deletion
+
+Command: `kubectl bilipro delete [options]`
+
+Deletes Deployment.
+v
+Optional Options:
+
+- `--namespace=`
+- `--name=`
+
+### Version
+
+Command: `kubectl bilipro version`
+
+Output the plugin version.
+
+
diff --git a/krew/cmd/kubectl-bilipro.go b/krew/cmd/kubectl-bilipro.go
new file mode 100644
index 000000000..8132bd0ec
--- /dev/null
+++ b/krew/cmd/kubectl-bilipro.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "os"
+
+ "github.com/spf13/pflag"
+
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd"
+ "k8s.io/cli-runtime/pkg/genericclioptions"
+)
+
+func main() {
+ flags := pflag.NewFlagSet("kubectl-bilipro", pflag.ExitOnError)
+ pflag.CommandLine = flags
+
+ cmd := cmd.NewExecutor(genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
+ if err := cmd.Execute(); err != nil {
+ os.Exit(1)
+ }
+}
diff --git a/krew/config.yaml b/krew/config.yaml
new file mode 100644
index 000000000..d19b59a8a
--- /dev/null
+++ b/krew/config.yaml
@@ -0,0 +1,5 @@
+- name: Ray_BiliBiliCookies__2
+ value: "cookie"
+ # DailyTrigger - required
+- name: Ray_DailyTaskConfig__Cron
+ value: "11 11 * * *"
\ No newline at end of file
diff --git a/krew/go.mod b/krew/go.mod
new file mode 100644
index 000000000..cf9f7d3fe
--- /dev/null
+++ b/krew/go.mod
@@ -0,0 +1,68 @@
+module github.com/RayWangQvQ/BiliBiliToolPro/krew
+
+go 1.18
+
+require (
+ github.com/spf13/cobra v1.4.0
+ github.com/spf13/pflag v1.0.5
+ k8s.io/api v0.25.4
+ k8s.io/cli-runtime v0.25.4
+ k8s.io/klog/v2 v2.70.1
+ sigs.k8s.io/kustomize/api v0.12.1
+ sigs.k8s.io/kustomize/kyaml v0.13.9
+ sigs.k8s.io/yaml v1.2.0
+)
+
+require (
+ github.com/PuerkitoBio/purell v1.1.1 // indirect
+ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/emicklei/go-restful/v3 v3.8.0 // indirect
+ github.com/evanphx/json-patch v4.12.0+incompatible // indirect
+ github.com/go-errors/errors v1.0.1 // indirect
+ github.com/go-logr/logr v1.2.3 // indirect
+ github.com/go-openapi/jsonpointer v0.19.5 // indirect
+ github.com/go-openapi/jsonreference v0.19.5 // indirect
+ github.com/go-openapi/swag v0.19.14 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/protobuf v1.5.2 // indirect
+ github.com/google/btree v1.0.1 // indirect
+ github.com/google/gnostic v0.5.7-v3refs // indirect
+ github.com/google/gofuzz v1.1.0 // indirect
+ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+ github.com/google/uuid v1.1.2 // indirect
+ github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
+ github.com/imdario/mergo v0.3.6 // indirect
+ github.com/inconshreveable/mousetrap v1.0.0 // indirect
+ github.com/josharian/intern v1.0.0 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
+ github.com/mailru/easyjson v0.7.6 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
+ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
+ github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/xlab/treeprint v1.1.0 // indirect
+ go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
+ golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
+ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
+ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f // indirect
+ golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
+ golang.org/x/text v0.3.7 // indirect
+ golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
+ google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.28.0 // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ gopkg.in/yaml.v3 v3.0.1 // indirect
+ k8s.io/apimachinery v0.25.4 // indirect
+ k8s.io/client-go v0.25.4 // indirect
+ k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
+ k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
+ sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+)
+
+replace github.com/RayWangQvQ/BiliBiliToolPro/krew => ../krew
diff --git a/krew/go.sum b/krew/go.sum
new file mode 100644
index 000000000..2f58a67d1
--- /dev/null
+++ b/krew/go.sum
@@ -0,0 +1,517 @@
+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/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/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/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+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/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/cpuguy83/go-md2man/v2 v2.0.1/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=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
+github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+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/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
+github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
+github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
+github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
+github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
+github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+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/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/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+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/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/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
+github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
+github.com/google/gnostic v0.5.7-v3refs h1:FhTMOKj2VhjpouxvWJAV1TL304uMlb9zcDqkl6cEI54=
+github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ=
+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.5/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/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.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/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/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
+github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
+github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
+github.com/google/uuid v1.1.2/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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+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/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
+github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+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/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/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/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
+github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
+github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
+github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+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/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+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/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
+github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
+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/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
+github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
+github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
+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=
+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.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
+go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
+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-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+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/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/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/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-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-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-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-20190827160401-ba9fcec4b297/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-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+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-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
+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/sys v0.0.0-20180830151530-49385e6e1522/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-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-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-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/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-20200122134326-e047566fdf82/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+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.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+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/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44=
+golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/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-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-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+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/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 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+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-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-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+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/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.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
+google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+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-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.2.2/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-20200615113413-eeeca48fe776/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=
+k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
+k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
+k8s.io/apimachinery v0.25.4 h1:CtXsuaitMESSu339tfhVXhQrPET+EiWnIY1rcurKnAc=
+k8s.io/apimachinery v0.25.4/go.mod h1:jaF9C/iPNM1FuLl7Zuy5b9v+n35HGSh6AQ4HYRkCqwo=
+k8s.io/cli-runtime v0.25.4 h1:GTSBN7aKBrc2LqpdO30CmHQqJtRmotxV7XsMSP+QZIk=
+k8s.io/cli-runtime v0.25.4/go.mod h1:JGOw1CR8v4Mcz6cEKA7bFQe0bPrNn1l5sGAX1/Ke4Eg=
+k8s.io/client-go v0.25.4 h1:3RNRDffAkNU56M/a7gUfXaEzdhZlYhoW8dgViGy5fn8=
+k8s.io/client-go v0.25.4/go.mod h1:8trHCAC83XKY0wsBIpbirZU4NTUpbuhc2JnI7OruGZw=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.70.1 h1:7aaoSdahviPmR+XkS7FyxlkkXs6tHISSG03RxleQAVQ=
+k8s.io/klog/v2 v2.70.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA=
+k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU=
+k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
+k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+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=
+sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 h1:iXTIw73aPyC+oRdyqqvVJuloN1p0AC/kzH07hu3NE+k=
+sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/kustomize/api v0.12.1 h1:7YM7gW3kYBwtKvoY216ZzY+8hM+lV53LUayghNRJ0vM=
+sigs.k8s.io/kustomize/api v0.12.1/go.mod h1:y3JUhimkZkR6sbLNwfJHxvo1TCLwuwm14sCYnkH6S1s=
+sigs.k8s.io/kustomize/kyaml v0.13.9 h1:Qz53EAaFFANyNgyOEJbT/yoIHygK40/ZcvU3rgry2Tk=
+sigs.k8s.io/kustomize/kyaml v0.13.9/go.mod h1:QsRbD0/KcU+wdk0/L0fIp2KLnohkVzs6fQ85/nOXac4=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/krew/pkg/cmd/cmd.go b/krew/pkg/cmd/cmd.go
new file mode 100644
index 000000000..5066f7a04
--- /dev/null
+++ b/krew/pkg/cmd/cmd.go
@@ -0,0 +1,39 @@
+package cmd
+
+import (
+ "log"
+
+ "github.com/spf13/cobra"
+ "k8s.io/cli-runtime/pkg/genericclioptions"
+)
+
+const (
+ biliproDesc = `Manage and deploy bilibili pro tools on k8s`
+ kubeconfig = "kubeconfig"
+)
+
+var (
+ confPath string
+ rootCmd = &cobra.Command{
+ Use: "bilipro",
+ Long: biliproDesc,
+ SilenceUsage: true,
+ }
+)
+
+func init() {
+ rootCmd.PersistentFlags().StringVar(&confPath, kubeconfig, "", "Custom kubeconfig path")
+
+ log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
+}
+
+// New creates a new root command for kubectl-bilipro
+func NewExecutor(streams genericclioptions.IOStreams) *cobra.Command {
+ cobra.EnableCommandSorting = false
+ rootCmd.AddCommand(newInitCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
+ // If you want to update, just init again
+ rootCmd.AddCommand(newGetCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
+ rootCmd.AddCommand(newDeleteCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
+ rootCmd.AddCommand(newVersionCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
+ return rootCmd
+}
diff --git a/krew/pkg/cmd/delete.go b/krew/pkg/cmd/delete.go
new file mode 100644
index 000000000..9483ae248
--- /dev/null
+++ b/krew/pkg/cmd/delete.go
@@ -0,0 +1,165 @@
+package cmd
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+ "strings"
+
+ "sigs.k8s.io/kustomize/api/krusty"
+ "sigs.k8s.io/kustomize/api/types"
+ "sigs.k8s.io/yaml"
+
+ "k8s.io/klog/v2"
+
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
+ "github.com/spf13/cobra"
+)
+
+const (
+ deleteDesc = `
+'delete' command delete bilibilipro tool.`
+ deleteExample = ` kubectl bilipro delete <--name deployment_name>`
+)
+
+type deleteCmd struct {
+ out io.Writer
+ errOut io.Writer
+ output bool
+ deployOpts options.DeployOptions
+}
+
+func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command {
+ o := &deleteCmd{out: out, errOut: errOut}
+
+ cmd := &cobra.Command{
+ Use: "delete",
+ Short: "Delete bilibilipro",
+ Long: deleteDesc,
+ Example: deleteExample,
+ Args: cobra.MaximumNArgs(0),
+ RunE: func(cmd *cobra.Command, args []string) error {
+
+ err := o.run(out)
+ if err != nil {
+ klog.Warning(err)
+ return err
+ }
+ return nil
+ },
+ }
+
+ f := cmd.Flags()
+ f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
+ f.StringVarP(&o.deployOpts.Name, "name", "", "bilibilipro", "name of deployment to delete")
+ return cmd
+}
+
+func (o *deleteCmd) run(writer io.Writer) error {
+ inDiskSys, err := utils.GetResourceFileSys()
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ // if the bilibili tool is deployed under system/pre-defined namespace, ignore the namespace file
+ resources := []string{}
+ if o.deployOpts.Namespace == "default" || o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
+ resources = []string{"bilipro/bilibiliPro"}
+ } else {
+ resources = []string{"bilipro/bilibiliPro", "bilipro/ns"}
+ }
+
+ // write the kustomization file
+
+ kustomizationYaml := types.Kustomization{
+ TypeMeta: types.TypeMeta{
+ Kind: "Kustomization",
+ APIVersion: "kustomize.config.k8s.io/v1beta1",
+ },
+ Resources: resources,
+ }
+
+ if o.deployOpts.Namespace != "" {
+ kustomizationYaml.Namespace = o.deployOpts.Namespace
+ }
+
+ // Compile the kustomization to a file and create on the in memory filesystem
+ kustYaml, err := yaml.Marshal(kustomizationYaml)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ kustFile, err := inDiskSys.Create("kustomization.yaml")
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ _, err = kustFile.Write(kustYaml)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ // kustomize build the target location
+ k := krusty.MakeKustomizer(
+ krusty.MakeDefaultOptions(),
+ )
+
+ m, err := k.Run(inDiskSys, "./bilipro")
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ yml, err := m.AsYaml()
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ if o.output {
+ _, err = writer.Write(yml)
+ klog.Error(err)
+ return err
+ }
+
+ // do kubectl delete
+ cmd := exec.Command("kubectl", "delete", "-f", "-")
+
+ cmd.Stdin = strings.NewReader(string(yml))
+
+ stdoutReader, _ := cmd.StdoutPipe()
+ stdoutScanner := bufio.NewScanner(stdoutReader)
+ go func() {
+ for stdoutScanner.Scan() {
+ fmt.Println(stdoutScanner.Text())
+ }
+ }()
+ stderrReader, _ := cmd.StderrPipe()
+ stderrScanner := bufio.NewScanner(stderrReader)
+ go func() {
+ for stderrScanner.Scan() {
+ fmt.Println(stderrScanner.Text())
+ }
+ }()
+ err = cmd.Start()
+ if err != nil {
+ fmt.Printf("Error : %v \n", err)
+ os.Exit(1)
+ }
+
+ // stuck here to wait for the completion
+ err = cmd.Wait()
+ if err != nil {
+ fmt.Printf("Error: %v \n", err)
+ os.Exit(1)
+ }
+
+ return nil
+}
diff --git a/krew/pkg/cmd/get.go b/krew/pkg/cmd/get.go
new file mode 100644
index 000000000..226183caa
--- /dev/null
+++ b/krew/pkg/cmd/get.go
@@ -0,0 +1,88 @@
+package cmd
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "os/exec"
+
+ "k8s.io/klog/v2"
+
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
+ "github.com/spf13/cobra"
+)
+
+const (
+ getDesc = `
+'get' command get bilibilipro tool deployment.`
+ getExample = ` kubectl bilipro get <--name deployment_name --namespace namespace_name>`
+)
+
+type getCmd struct {
+ out io.Writer
+ errOut io.Writer
+
+ deployOpts options.DeployOptions
+}
+
+func newGetCmd(out io.Writer, errOut io.Writer) *cobra.Command {
+ o := &getCmd{out: out, errOut: errOut}
+
+ cmd := &cobra.Command{
+ Use: "get",
+ Short: "Get bilibilipro",
+ Long: getDesc,
+ Example: getExample,
+ Args: cobra.MaximumNArgs(0),
+ RunE: func(cmd *cobra.Command, args []string) error {
+
+ err := o.run(out)
+ if err != nil {
+ klog.Warning(err)
+ return err
+ }
+ return nil
+ },
+ }
+
+ f := cmd.Flags()
+ f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
+ f.StringVarP(&o.deployOpts.Name, "name", "", "bilibilipro", "name of deployment to get")
+ return cmd
+}
+
+func (o *getCmd) run(writer io.Writer) error {
+ // do kubectl get
+ cmd := exec.Command("kubectl", "get", "deploy", o.deployOpts.Name, "-n", o.deployOpts.Namespace)
+
+ stdoutReader, _ := cmd.StdoutPipe()
+ stdoutScanner := bufio.NewScanner(stdoutReader)
+ go func() {
+ for stdoutScanner.Scan() {
+ fmt.Println(stdoutScanner.Text())
+ }
+ }()
+ stderrReader, _ := cmd.StderrPipe()
+ stderrScanner := bufio.NewScanner(stderrReader)
+ go func() {
+ for stderrScanner.Scan() {
+ fmt.Println(stderrScanner.Text())
+ }
+ }()
+
+ err := cmd.Start()
+ if err != nil {
+ fmt.Printf("Error : %v \n", err)
+ os.Exit(1)
+ }
+
+ // stuck here to wait for the completion
+ err = cmd.Wait()
+ if err != nil {
+ fmt.Printf("Error: %v \n", err)
+ os.Exit(1)
+ }
+
+ return nil
+}
diff --git a/krew/pkg/cmd/init.go b/krew/pkg/cmd/init.go
new file mode 100644
index 000000000..69c8a5564
--- /dev/null
+++ b/krew/pkg/cmd/init.go
@@ -0,0 +1,255 @@
+package cmd
+
+import (
+ "bufio"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+
+ corev1 "k8s.io/api/core/v1"
+
+ "sigs.k8s.io/kustomize/kyaml/resid"
+
+ "sigs.k8s.io/yaml"
+
+ "sigs.k8s.io/kustomize/api/types"
+
+ "k8s.io/klog/v2"
+
+ "github.com/spf13/cobra"
+
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
+ "sigs.k8s.io/kustomize/api/krusty"
+)
+
+const (
+ initDesc = `
+ 'init' command creates BilibiliPro deployment along with all the dependencies.`
+ initExample = ` kubectl bilipro init --config `
+)
+
+type initCmd struct {
+ out io.Writer
+ errOut io.Writer
+ output bool
+ deployOpts options.DeployOptions
+}
+
+func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command {
+ o := &initCmd{out: out, errOut: errOut}
+
+ cmd := &cobra.Command{
+ Use: "init",
+ Short: "Initialize bilipro",
+ Long: initDesc,
+ Example: initExample,
+ Args: cobra.MaximumNArgs(0),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ err := o.run(out)
+ if err != nil {
+ klog.Warning(err)
+ return err
+ }
+ return nil
+ },
+ }
+
+ f := cmd.Flags()
+ f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:0.2.1", "bilibilipro image")
+ f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
+ f.StringVar(&o.deployOpts.ImagePullSecret, "image-pull-secret", "", "image pull secret to be used for pulling bilibilipro image")
+ f.StringVarP(&o.deployOpts.ConfigFilePath, "config", "c", "", "the config file contanis the environment variables")
+ f.BoolVarP(&o.output, "output", "o", false, "dry run this command and generate requisite yaml")
+ return cmd
+}
+
+type opStr struct {
+ Op string `json:"op"`
+ Path string `json:"path"`
+ Value string `json:"value"`
+}
+
+type opInterface struct {
+ Op string `json:"op"`
+ Path string `json:"path"`
+ Value interface{} `json:"value"`
+}
+
+type normalEnvVars struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+}
+
+// run initializes local config and installs BiliBiliPro tool to Kubernetes Cluster.
+func (o *initCmd) run(writer io.Writer) error {
+ inDiskSys, err := utils.GetResourceFileSys()
+ if err != nil {
+ return err
+ }
+
+ // if the bilibili tool is deployed under system/pre-defined namespace, ignore the namespace file
+ resources := []string{}
+ if o.deployOpts.Namespace == "default" || o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
+ resources = []string{"bilipro/bilibiliPro"}
+ } else {
+ resources = []string{"bilipro/ns", "bilipro/bilibiliPro"}
+ }
+
+ // write the kustomization file
+ kustomizationYaml := types.Kustomization{
+ TypeMeta: types.TypeMeta{
+ Kind: "Kustomization",
+ APIVersion: "kustomize.config.k8s.io/v1beta1",
+ },
+ Resources: resources,
+ PatchesJson6902: []types.Patch{},
+ }
+
+ var deployDepPatches []interface{}
+ // create patches for the supplied arguments
+ if o.deployOpts.Image != "" {
+ deployDepPatches = append(deployDepPatches, opStr{
+ Op: "replace",
+ Path: "/spec/template/spec/containers/0/image",
+ Value: o.deployOpts.Image,
+ })
+ }
+ // create patches for the env
+ content, err := ioutil.ReadFile(o.deployOpts.ConfigFilePath)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ envs := []normalEnvVars{}
+ err = yaml.Unmarshal(content, &envs)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ deployDepPatches = append(deployDepPatches, opInterface{
+ Op: "add",
+ Path: "/spec/template/spec/containers/0/env",
+ Value: envs,
+ })
+
+ if o.deployOpts.ImagePullSecret != "" {
+ deployDepPatches = append(deployDepPatches, opInterface{
+ Op: "add",
+ Path: "/spec/template/spec/imagePullSecrets",
+ Value: []corev1.LocalObjectReference{{Name: o.deployOpts.ImagePullSecret}},
+ })
+ }
+
+ // attach the patches to the kustomization file
+ if len(deployDepPatches) > 0 {
+ kustomizationYaml.PatchesJson6902 = append(kustomizationYaml.PatchesJson6902, types.Patch{
+ Patch: o.serializeJSONPatchOps(deployDepPatches),
+ Target: &types.Selector{
+ ResId: resid.ResId{
+ Gvk: resid.Gvk{
+ Group: "apps",
+ Version: "v1",
+ Kind: "Deployment",
+ },
+ Name: "bilibilipro",
+ },
+ },
+ })
+ }
+
+ // Not deploying in kube-* namespace
+ if o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
+ fmt.Println("better not deployed under system namesapce")
+ }
+
+ if o.deployOpts.Namespace != "" {
+ kustomizationYaml.Namespace = o.deployOpts.Namespace
+ }
+ // Compile the kustomization to a file and create on the in memory filesystem
+ kustYaml, err := yaml.Marshal(kustomizationYaml)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ kustFile, err := inDiskSys.Create("kustomization.yaml")
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ _, err = kustFile.Write(kustYaml)
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ // kustomize build the target location
+ k := krusty.MakeKustomizer(
+ krusty.MakeDefaultOptions(),
+ )
+
+ m, err := k.Run(inDiskSys, "./bilipro")
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ yml, err := m.AsYaml()
+ if err != nil {
+ klog.Error(err)
+ return err
+ }
+
+ if o.output {
+ _, err = writer.Write(yml)
+ klog.Error(err)
+ return err
+ }
+
+ // do kubectl apply
+ cmd := exec.Command("kubectl", "apply", "-f", "-")
+
+ cmd.Stdin = strings.NewReader(string(yml))
+
+ stdoutReader, _ := cmd.StdoutPipe()
+ stdoutScanner := bufio.NewScanner(stdoutReader)
+ go func() {
+ for stdoutScanner.Scan() {
+ fmt.Println(stdoutScanner.Text())
+ }
+ }()
+ stderrReader, _ := cmd.StderrPipe()
+ stderrScanner := bufio.NewScanner(stderrReader)
+ go func() {
+ for stderrScanner.Scan() {
+ fmt.Println(stderrScanner.Text())
+ }
+ }()
+ err = cmd.Start()
+ if err != nil {
+ fmt.Printf("Error : %v \n", err)
+ os.Exit(1)
+ }
+
+ // Stuck here until there are out and err
+ err = cmd.Wait()
+ if err != nil {
+ fmt.Printf("Error: %v \n", err)
+ os.Exit(1)
+ }
+
+ return nil
+}
+
+func (o *initCmd) serializeJSONPatchOps(jp []interface{}) string {
+ jpJSON, _ := json.Marshal(jp)
+ return string(jpJSON)
+}
diff --git a/krew/pkg/cmd/version.go b/krew/pkg/cmd/version.go
new file mode 100644
index 000000000..f7b05283a
--- /dev/null
+++ b/krew/pkg/cmd/version.go
@@ -0,0 +1,52 @@
+package cmd
+
+import (
+ "fmt"
+ "io"
+
+ "k8s.io/klog/v2"
+
+ "github.com/spf13/cobra"
+)
+
+// version provides the version of this plugin
+var version = "NO.VERSION"
+
+const (
+ versionDesc = `
+'version' command displays the kubectl plugin version.`
+ versionExample = ` kubectl bilipro version`
+)
+
+type versionCmd struct {
+ out io.Writer
+ errOut io.Writer
+}
+
+func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command {
+ o := &versionCmd{out: out, errOut: errOut}
+
+ cmd := &cobra.Command{
+ Use: "version",
+ Short: "Display plugin version",
+ Long: versionDesc,
+ Example: versionExample,
+ Args: cobra.MaximumNArgs(0),
+ RunE: func(cmd *cobra.Command, args []string) error {
+ err := o.run()
+ if err != nil {
+ klog.Warning(err)
+ return err
+ }
+ return nil
+ },
+ }
+
+ return cmd
+}
+
+// run initializes local config and installs BilibiliPro Plugin to Kubernetes cluster.
+func (o *versionCmd) run() error {
+ fmt.Println(version)
+ return nil
+}
diff --git a/krew/pkg/options/deployment.go b/krew/pkg/options/deployment.go
new file mode 100644
index 000000000..4382e85cb
--- /dev/null
+++ b/krew/pkg/options/deployment.go
@@ -0,0 +1,10 @@
+package options
+
+// DeployOptions encapsulates the CLI options for a BiliBiliPro
+type DeployOptions struct {
+ Name string
+ Image string
+ Namespace string
+ ImagePullSecret string
+ ConfigFilePath string
+}
diff --git a/krew/pkg/resources/asset.go b/krew/pkg/resources/asset.go
new file mode 100644
index 000000000..20cea3136
--- /dev/null
+++ b/krew/pkg/resources/asset.go
@@ -0,0 +1,13 @@
+package resources
+
+import (
+ "embed"
+)
+
+//go:embed *
+var fs embed.FS
+
+// GetStaticResources returns the fs with the embedded assets
+func GetStaticResources() embed.FS {
+ return fs
+}
diff --git a/krew/pkg/resources/base/bilibiliPro/deployment.yaml b/krew/pkg/resources/base/bilibiliPro/deployment.yaml
new file mode 100644
index 000000000..df8c8008e
--- /dev/null
+++ b/krew/pkg/resources/base/bilibiliPro/deployment.yaml
@@ -0,0 +1,18 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: bilibilipro
+spec:
+ selector:
+ matchLabels:
+ app: bilibilipro
+ template:
+ metadata:
+ labels:
+ app: bilibilipro
+ spec:
+ containers:
+ - name: bilibilipro
+ image: zai7lou/bilibili_tool_pro:0.2.1
+ imagePullPolicy: IfNotPresent
+
\ No newline at end of file
diff --git a/krew/pkg/resources/base/bilibiliPro/kustomization.yaml b/krew/pkg/resources/base/bilibiliPro/kustomization.yaml
new file mode 100644
index 000000000..991a8834e
--- /dev/null
+++ b/krew/pkg/resources/base/bilibiliPro/kustomization.yaml
@@ -0,0 +1,2 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
\ No newline at end of file
diff --git a/krew/pkg/resources/base/kustomization.yaml b/krew/pkg/resources/base/kustomization.yaml
new file mode 100644
index 000000000..991a8834e
--- /dev/null
+++ b/krew/pkg/resources/base/kustomization.yaml
@@ -0,0 +1,2 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
\ No newline at end of file
diff --git a/krew/pkg/resources/base/ns/kustomization.yaml b/krew/pkg/resources/base/ns/kustomization.yaml
new file mode 100644
index 000000000..991a8834e
--- /dev/null
+++ b/krew/pkg/resources/base/ns/kustomization.yaml
@@ -0,0 +1,2 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
\ No newline at end of file
diff --git a/krew/pkg/resources/base/ns/namespace.yaml b/krew/pkg/resources/base/ns/namespace.yaml
new file mode 100644
index 000000000..6057bc06d
--- /dev/null
+++ b/krew/pkg/resources/base/ns/namespace.yaml
@@ -0,0 +1,5 @@
+
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: bilipro
\ No newline at end of file
diff --git a/krew/pkg/resources/kustomization.yaml b/krew/pkg/resources/kustomization.yaml
new file mode 100644
index 000000000..b929f13d0
--- /dev/null
+++ b/krew/pkg/resources/kustomization.yaml
@@ -0,0 +1,7 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+resources:
+ - base/ns/namespace.yaml
+ - base/bilibiliPro/deployment.yaml
+
\ No newline at end of file
diff --git a/krew/pkg/utils/utils.go b/krew/pkg/utils/utils.go
new file mode 100644
index 000000000..504d02de2
--- /dev/null
+++ b/krew/pkg/utils/utils.go
@@ -0,0 +1,82 @@
+package utils
+
+import (
+ "io"
+ "io/fs"
+ "log"
+ "path"
+ "strings"
+
+ "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/resources"
+ "sigs.k8s.io/kustomize/kyaml/filesys"
+)
+
+var assetFS = resources.GetStaticResources()
+
+// GetResourceFileSys file
+func GetResourceFileSys() (filesys.FileSystem, error) {
+ inDiskSys := filesys.MakeFsOnDisk()
+ // copy from the resources into the target folder on the in memory FS
+ if err := copyDirtoDiskFS(".", "bilipro", inDiskSys); err != nil {
+ log.Println(err)
+ return nil, err
+ }
+ return inDiskSys, nil
+}
+
+func copyFileToDiskFS(src, dst string, diskFS filesys.FileSystem) error {
+ // skip all .go files
+ if strings.HasSuffix(src, ".go") {
+ return nil
+ }
+ var err error
+ var srcFileDesc fs.File
+ var dstFileDesc filesys.File
+
+ if srcFileDesc, err = assetFS.Open(src); err != nil {
+ return err
+ }
+ defer srcFileDesc.Close()
+
+ if dstFileDesc, err = diskFS.Create(dst); err != nil {
+ return err
+ }
+ defer dstFileDesc.Close()
+
+ // Note: I had to read the whole string, for some reason io.Copy was not copying the whole content
+ input, err := io.ReadAll(srcFileDesc)
+ if err != nil {
+ return err
+ }
+
+ _, err = dstFileDesc.Write(input)
+ return err
+}
+
+func copyDirtoDiskFS(src string, dst string, diskFS filesys.FileSystem) error {
+ var err error
+ var fds []fs.DirEntry
+
+ if err = diskFS.MkdirAll(dst); err != nil {
+ return err
+ }
+
+ if fds, err = assetFS.ReadDir(src); err != nil {
+ return err
+ }
+ for _, fd := range fds {
+ srcfp := path.Join(src, fd.Name())
+ dstfp := path.Join(dst, fd.Name())
+
+ if fd.IsDir() {
+ if err = copyDirtoDiskFS(srcfp, dstfp, diskFS); err != nil {
+ return err
+ }
+ } else {
+ if err = copyFileToDiskFS(srcfp, dstfp, diskFS); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/podman/README.md b/podman/README.md
index 6aef954b8..6956c4a2e 100644
--- a/podman/README.md
+++ b/podman/README.md
@@ -7,6 +7,7 @@
- [2. 运行容器](#2-运行容器)
- [2.1. 极简版](#21-极简版)
- [2.2. 综合版](#22-综合版)
+- [登录](#登录)
- [3. 自己构建镜像(非必须)](#3-自己构建镜像非必须)
- [4. 其他](#4-其他)
@@ -52,9 +53,7 @@ Podman可以和Docker共存,命令也基本可以通用。
```
# 生成并运行容器
-podman run -itd --name="bili" \
- -e Ray_BiliBiliCookies__1="cookie" \
- docker.io/zai7lou/bilibili_tool_pro
+podman run -itd --name="bili" docker.io/zai7lou/bilibili_tool_pro
# 查看实时日志
podman logs -f bili
@@ -71,13 +70,13 @@ mkdir -p Logs
# 下载appsettings.json
wget https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/src/Ray.BiliBiliTool.Console/appsettings.json
+wget https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/docker/sample/cookies.json
# 运行
podman run -itd --name="bili" \
-v /bili/Logs:/app/Logs \
-v /bili/appsettings.json:/app/appsettings.json \
- -e Ray_BiliBiliCookies__1="cookie" \
- -e Ray_BiliBiliCookies__2="cookie" \
+ -v /bili/cookies.json:/app/cookies.json \
-e Ray_DailyTaskConfig__Cron="0 15 * * *" \
-e Ray_LiveLotteryTaskConfig__Cron="0 22 * * *" \
-e Ray_UnfollowBatchedTaskConfig__Cron="0 6 1 * *" \
@@ -99,6 +98,14 @@ podman ps -a
podman exec -it bili bash
```
+## 登录
+
+在宿主机运行`podman exec -it bili bash -c "dotnet Ray.BiliBiliTool.Console.dll --runTasks=Login"`
+
+扫码进行登录。
+
+![login](../docs/imgs/docker-login.png)
+
## 3. 自己构建镜像(非必须)
目前我提供和维护的镜像:`[zai7lou/bilibili_tool_pro](https://hub.docker.com/repository/docker/zai7lou/bilibili_tool_pro)`;
diff --git a/qinglong/DefaultTasks/bili_task_base.sh b/qinglong/DefaultTasks/bili_task_base.sh
index 3b8d15d41..5dfeea189 100644
--- a/qinglong/DefaultTasks/bili_task_base.sh
+++ b/qinglong/DefaultTasks/bili_task_base.sh
@@ -18,4 +18,5 @@ echo -e "\nrepo目录: $dir_repo"
bili_repo_dir="$(find $dir_repo -type d -iname $bili_repo | head -1)"
echo -e "bili仓库目录: $bili_repo_dir\n"
-cd $bili_repo_dir
\ No newline at end of file
+cd $bili_repo_dir
+export Ray_PlateformType=QingLong
\ No newline at end of file
diff --git a/qinglong/DefaultTasks/bili_task_daily.sh b/qinglong/DefaultTasks/bili_task_daily.sh
index 55cef2f06..e9ebd6adc 100644
--- a/qinglong/DefaultTasks/bili_task_daily.sh
+++ b/qinglong/DefaultTasks/bili_task_daily.sh
@@ -4,6 +4,6 @@
. bili_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=Daily && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_task_liveLottery.sh b/qinglong/DefaultTasks/bili_task_liveLottery.sh
index b3caa3b0c..9c209094f 100644
--- a/qinglong/DefaultTasks/bili_task_liveLottery.sh
+++ b/qinglong/DefaultTasks/bili_task_liveLottery.sh
@@ -4,6 +4,6 @@
. bili_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=LiveLottery && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_task_login.sh b/qinglong/DefaultTasks/bili_task_login.sh
new file mode 100644
index 000000000..3ff547614
--- /dev/null
+++ b/qinglong/DefaultTasks/bili_task_login.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# new Env("bili扫码登录")
+# cron 0 0 1 1 * bili_task_login.sh
+. bili_task_base.sh
+
+cd ./src/Ray.BiliBiliTool.Console
+
+export Ray_RunTasks=Login && \
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_task_test.sh b/qinglong/DefaultTasks/bili_task_test.sh
index 38e740aaa..bf18cf76e 100644
--- a/qinglong/DefaultTasks/bili_task_test.sh
+++ b/qinglong/DefaultTasks/bili_task_test.sh
@@ -4,6 +4,6 @@
. bili_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=Test && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_task_unfollowBatched.sh b/qinglong/DefaultTasks/bili_task_unfollowBatched.sh
index 7fa37a101..0db839f19 100644
--- a/qinglong/DefaultTasks/bili_task_unfollowBatched.sh
+++ b/qinglong/DefaultTasks/bili_task_unfollowBatched.sh
@@ -4,6 +4,6 @@
. bili_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=UnfollowBatched && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_task_vipBigPoint.sh b/qinglong/DefaultTasks/bili_task_vipBigPoint.sh
index f6f9792a2..da6baffec 100644
--- a/qinglong/DefaultTasks/bili_task_vipBigPoint.sh
+++ b/qinglong/DefaultTasks/bili_task_vipBigPoint.sh
@@ -4,6 +4,6 @@
. bili_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=VipBigPoint && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_dev_task_base.sh b/qinglong/DefaultTasks/dev/bili_dev_task_base.sh
similarity index 92%
rename from qinglong/DefaultTasks/bili_dev_task_base.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_base.sh
index 6da1c3a65..40a6fa5a2 100644
--- a/qinglong/DefaultTasks/bili_dev_task_base.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_base.sh
@@ -18,4 +18,5 @@ echo -e "\nrepo目录: $dir_repo"
bili_repo_dir="$(find $dir_repo -type d -iname $bili_repo | head -1)"
echo -e "bili仓库目录: $bili_repo_dir\n"
-cd $bili_repo_dir
\ No newline at end of file
+cd $bili_repo_dir
+export Ray_PlateformType=QingLong
\ No newline at end of file
diff --git a/qinglong/DefaultTasks/bili_dev_task_daily.sh b/qinglong/DefaultTasks/dev/bili_dev_task_daily.sh
similarity index 80%
rename from qinglong/DefaultTasks/bili_dev_task_daily.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_daily.sh
index 574d3d0df..6b30dd4e5 100644
--- a/qinglong/DefaultTasks/bili_dev_task_daily.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_daily.sh
@@ -4,6 +4,6 @@
. bili_dev_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=Daily && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_dev_task_liveLottery.sh b/qinglong/DefaultTasks/dev/bili_dev_task_liveLottery.sh
similarity index 81%
rename from qinglong/DefaultTasks/bili_dev_task_liveLottery.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_liveLottery.sh
index 521b03a48..eb2c20124 100644
--- a/qinglong/DefaultTasks/bili_dev_task_liveLottery.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_liveLottery.sh
@@ -5,6 +5,5 @@
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
export Ray_RunTasks=LiveLottery && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/dev/bili_dev_task_login.sh b/qinglong/DefaultTasks/dev/bili_dev_task_login.sh
new file mode 100644
index 000000000..933e05cfa
--- /dev/null
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_login.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+# new Env("bili扫码登录[dev先行版]")
+# cron 0 0 1 1 * bili_dev_task_login.sh
+. bili_dev_task_base.sh
+
+cd ./src/Ray.BiliBiliTool.Console
+
+export Ray_RunTasks=Login && \
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_dev_task_test.sh b/qinglong/DefaultTasks/dev/bili_dev_task_test.sh
similarity index 80%
rename from qinglong/DefaultTasks/bili_dev_task_test.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_test.sh
index a175c5bd5..19c6f798e 100644
--- a/qinglong/DefaultTasks/bili_dev_task_test.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_test.sh
@@ -4,6 +4,6 @@
. bili_dev_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=Test && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_dev_task_tryFix.sh b/qinglong/DefaultTasks/dev/bili_dev_task_tryFix.sh
similarity index 100%
rename from qinglong/DefaultTasks/bili_dev_task_tryFix.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_tryFix.sh
diff --git a/qinglong/DefaultTasks/bili_dev_task_unfollowBatched.sh b/qinglong/DefaultTasks/dev/bili_dev_task_unfollowBatched.sh
similarity index 82%
rename from qinglong/DefaultTasks/bili_dev_task_unfollowBatched.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_unfollowBatched.sh
index 71cd7be83..0f8311dba 100644
--- a/qinglong/DefaultTasks/bili_dev_task_unfollowBatched.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_unfollowBatched.sh
@@ -4,6 +4,6 @@
. bili_dev_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=UnfollowBatched && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/DefaultTasks/bili_dev_task_vipBigPoint.sh b/qinglong/DefaultTasks/dev/bili_dev_task_vipBigPoint.sh
similarity index 82%
rename from qinglong/DefaultTasks/bili_dev_task_vipBigPoint.sh
rename to qinglong/DefaultTasks/dev/bili_dev_task_vipBigPoint.sh
index 3dbcfbb8e..d6cc9d4de 100644
--- a/qinglong/DefaultTasks/bili_dev_task_vipBigPoint.sh
+++ b/qinglong/DefaultTasks/dev/bili_dev_task_vipBigPoint.sh
@@ -4,6 +4,6 @@
. bili_dev_task_base.sh
cd ./src/Ray.BiliBiliTool.Console
-export ENVIRONMENT=Production && \
+
export Ray_RunTasks=VipBigPoint && \
-dotnet run
+dotnet run --ENVIRONMENT=Production
diff --git a/qinglong/README.md b/qinglong/README.md
index 8a43d2827..34313140b 100644
--- a/qinglong/README.md
+++ b/qinglong/README.md
@@ -10,16 +10,16 @@
- [1.1. 安装 `dotnet` 环境](#11-安装-dotnet-环境)
- [1.2. 重启青龙容器](#12-重启青龙容器)
- [1.3. 登录青龙面板并修改配置](#13-登录青龙面板并修改配置)
- - [1.4. 添加bili配置](#14-添加bili配置)
- - [1.5. 在青龙面板中添加拉库定时任务](#15-在青龙面板中添加拉库定时任务)
- - [1.5.1 订阅管理](#151-订阅管理)
- - [1.5.2 定时任务拉库](#152-定时任务拉库)
+ - [1.4. 在青龙面板中添加拉库定时任务](#14-在青龙面板中添加拉库定时任务)
+ - [1.4.1. 订阅管理](#141-订阅管理)
+ - [1.4.2. 定时任务拉库](#142-定时任务拉库)
+ - [1.5. 登录](#15-登录)
- [2. 先行版](#2-先行版)
- - [2.1 订阅管理](#21-订阅管理)
- - [2.2 定时任务拉库](#22-定时任务拉库)
+ - [2.1. 订阅管理](#21-订阅管理)
+ - [2.2. 定时任务拉库](#22-定时任务拉库)
- [3. GitHub加速](#3-github加速)
-- [4 常见问题](#4-常见问题)
- - [4.1 Couldn't find a valid ICU package installed on the system](#41-couldnt-find-a-valid-icu-package-installed-on-the-system)
+- [4. 常见问题](#4-常见问题)
+ - [4.1. Couldn't find a valid ICU package installed on the system](#41-couldnt-find-a-valid-icu-package-installed-on-the-system)
@@ -53,29 +53,10 @@ curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliB
保存配置。
-### 1.4. 添加bili配置
-
-青龙面板,`环境变量`页,添加环境变量:
-
-```
-名称:Ray_BiliBiliCookies__1
-值:abc
-```
-
-```
-名称:Ray_BiliBiliCookies__2
-值:defg
-```
-
-`abc`、`defg`为你抓取到的真实cookie字符串。
-
-![qinglong-env.png](../docs/imgs/qinglong-env.png)
-
-
-### 1.5. 在青龙面板中添加拉库定时任务
+### 1.4. 在青龙面板中添加拉库定时任务
两种方式:
-#### 1.5.1 订阅管理
+#### 1.4.1. 订阅管理
```
名称:Bilibili
@@ -91,7 +72,7 @@ curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliB
保存后,点击运行按钮,运行拉库。
-#### 1.5.2 定时任务拉库
+#### 1.4.2. 定时任务拉库
青龙面板,`定时任务`页,右上角`添加任务`,填入以下信息:
```
@@ -108,6 +89,15 @@ curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliB
![qinglong-tasks.png](../docs/imgs/qinglong-tasks.png)
+### 1.5. 登录
+
+在青龙定时任务中,点击运行`bili扫码登录`任务,查看运行日志,扫描日志中的二维码进行登录。
+![qinglong-login.png](../docs/imgs/qinglong-login.png)
+
+登录成功后,会将cookie保存到青龙的环境变量中:
+
+![qinglong-env.png](../docs/imgs/qinglong-env.png)
+
## 2. 先行版
青龙拉库时可以指定分支,develop分支的代码会超前于默认的main分支,包含当前正在开发的新功能。
@@ -116,7 +106,7 @@ curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliB
方式有两种:
-### 2.1 订阅管理
+### 2.1. 订阅管理
```
分支:develop
@@ -125,16 +115,16 @@ curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliB
其他选项同上。
-### 2.2 定时任务拉库
+### 2.2. 定时任务拉库
修改拉库命令为`ql repo https://github.com/RayWangQvQ/BiliBiliToolPro.git "bili_dev_task_" "" "" "develop"`
## 3. GitHub加速
拉库时,如果服务器在国内,访问GitHub速度慢,可以在仓库地址前加上 `https://ghproxy.com/` 进行加速, 如:`ql repo https://ghproxy.com/https://github.com/RayWangQvQ/BiliBiliToolPro.git "bili_task_"`
-## 4 常见问题
+## 4. 常见问题
-### 4.1 Couldn't find a valid ICU package installed on the system
+### 4.1. Couldn't find a valid ICU package installed on the system
如 #266 ,需要在青龙面板的环境变量添加如下环境变量:
diff --git a/qinglong/bak/bili_dev_task_get_cookie.py.bak b/qinglong/bak/bili_dev_task_get_cookie.py.bak
new file mode 100644
index 000000000..7cf0e8304
--- /dev/null
+++ b/qinglong/bak/bili_dev_task_get_cookie.py.bak
@@ -0,0 +1,87 @@
+'''
+1 9 11 11 1 bili_dev_task_get_cookie.py
+手动运行,查看日志,并使用手机B站app扫描日志中二维码,注意,只能修改第一个cookie
+如果产生错误,重新运行并用手机扫描二维码
+有可能识别不出来二维码,我测试了几次都能识别
+
+默认环境变量存放位置为/ql/data/config/env.sh
+可以自己通过docker命令进入容器查找这个文件位置。docker exec -it qinglong /bin/bash,进入青龙容器,然后查找一下这个文件位置
+filename = '../config/env.sh'
+'''
+
+import qrcode
+import requests
+import json
+import time
+import os
+
+filename = '/ql/data/config/env.sh'
+
+url_get = 'http://passport.bilibili.com/x/passport-login/web/qrcode/generate'
+headers = {
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.42"
+ }
+session = requests.session()
+response = session.get(url_get, headers=headers)
+json_data = json.loads(response.text)
+qr_data = json_data['data']['url']
+qr_code = json_data['data']['qrcode_key']
+# print(qr_data)
+# img = qrcode.make(qr_data)
+# img.save('../upload/B.png')
+# 生成二维码,并且打印,只有invert是True手机才能识别,默认的打印识别不出来
+qr = qrcode.QRCode()
+qr.add_data(qr_data)
+qr.print_ascii(invert=True)
+
+url_get_2 = f'http://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key={qr_code}&source=main_mini'
+refresh_token = ''
+# 尝试次数
+try_time = 8
+while True:
+ try_time -= 1
+ if not try_time:
+ print('一直没有扫码,退出登录!')
+ exit(1)
+ response = session.get(url_get_2, headers=headers)
+ json_data = json.loads(response.text)
+ response_data_2 = json_data['data']
+ if response_data_2['code'] == 0:
+ try_time += 5
+ refresh_token = response_data_2['refresh_token']
+ print(response_data_2, end='')
+ if response_data_2['message'] == '二维码已失效':
+ print(response_data_2['message'])
+ print('-' * 20)
+ break
+ print(response_data_2['message'])
+ print('-' * 20)
+ time.sleep(5)
+session.get('https://api.bilibili.com/x/web-interface/nav')
+cookies = requests.utils.dict_from_cookiejar(session.cookies)
+lst = []
+for item in cookies.items():
+ lst.append(f"{item[0]}={item[1]}")
+
+cookie_str = ';'.join(lst)
+print('=' * 20)
+print(cookie_str)
+print('=' * 20)
+# 修改环境变量
+with open(filename, 'r') as f:
+ lines = f.readlines()
+
+flag = True
+with open(filename, 'w') as f:
+ for l in lines:
+ if 'Ray_BiliBiliCookies__1' in l:
+ flag = False
+ l = f'export Ray_BiliBiliCookies__1="{cookie_str}"\n'
+ print(l)
+ f.write(l)
+ if flag:
+ flag = False
+ l = f'export Ray_BiliBiliCookies__1="{cookie_str}"\n'
+ print(l)
+ f.write(l)
+os.popen(f'source {filename}')
diff --git a/qinglong/bak/bili_task_get_cookie.py.bak b/qinglong/bak/bili_task_get_cookie.py.bak
new file mode 100644
index 000000000..9243a6387
--- /dev/null
+++ b/qinglong/bak/bili_task_get_cookie.py.bak
@@ -0,0 +1,87 @@
+'''
+1 9 11 11 1 bili_task_get_cookie.py
+手动运行,查看日志,并使用手机B站app扫描日志中二维码,注意,只能修改第一个cookie
+如果产生错误,重新运行并用手机扫描二维码
+有可能识别不出来二维码,我测试了几次都能识别
+
+默认环境变量存放位置为/ql/data/config/env.sh
+可以自己通过docker命令进入容器查找这个文件位置。docker exec -it qinglong /bin/bash,进入青龙容器,然后查找一下这个文件位置
+filename = '../config/env.sh'
+'''
+
+import qrcode
+import requests
+import json
+import time
+import os
+
+filename = '/ql/data/config/env.sh'
+
+url_get = 'http://passport.bilibili.com/x/passport-login/web/qrcode/generate'
+headers = {
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36 Edg/108.0.1462.42"
+ }
+session = requests.session()
+response = session.get(url_get, headers=headers)
+json_data = json.loads(response.text)
+qr_data = json_data['data']['url']
+qr_code = json_data['data']['qrcode_key']
+# print(qr_data)
+# img = qrcode.make(qr_data)
+# img.save('../upload/B.png')
+# 生成二维码,并且打印,只有invert是True手机才能识别,默认的打印识别不出来
+qr = qrcode.QRCode()
+qr.add_data(qr_data)
+qr.print_ascii(invert=True)
+
+url_get_2 = f'http://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key={qr_code}&source=main_mini'
+refresh_token = ''
+# 尝试次数
+try_time = 8
+while True:
+ try_time -= 1
+ if not try_time:
+ print('一直没有扫码,退出登录!')
+ exit(1)
+ response = session.get(url_get_2, headers=headers)
+ json_data = json.loads(response.text)
+ response_data_2 = json_data['data']
+ if response_data_2['code'] == 0:
+ try_time += 5
+ refresh_token = response_data_2['refresh_token']
+ print(response_data_2, end='')
+ if response_data_2['message'] == '二维码已失效':
+ print(response_data_2['message'])
+ print('-' * 20)
+ break
+ print(response_data_2['message'])
+ print('-' * 20)
+ time.sleep(5)
+session.get('https://api.bilibili.com/x/web-interface/nav')
+cookies = requests.utils.dict_from_cookiejar(session.cookies)
+lst = []
+for item in cookies.items():
+ lst.append(f"{item[0]}={item[1]}")
+
+cookie_str = ';'.join(lst)
+print('=' * 20)
+print(cookie_str)
+print('=' * 20)
+# 修改环境变量
+with open(filename, 'r') as f:
+ lines = f.readlines()
+
+flag = True
+with open(filename, 'w') as f:
+ for l in lines:
+ if 'Ray_BiliBiliCookies__1' in l:
+ flag = False
+ l = f'export Ray_BiliBiliCookies__1="{cookie_str}"\n'
+ print(l)
+ f.write(l)
+ if flag:
+ flag = False
+ l = f'export Ray_BiliBiliCookies__1="{cookie_str}"\n'
+ print(l)
+ f.write(l)
+os.popen(f'source {filename}')
diff --git a/qinglong/extra.sh b/qinglong/extra.sh
index c5f16c828..9d3840a3e 100644
--- a/qinglong/extra.sh
+++ b/qinglong/extra.sh
@@ -5,4 +5,6 @@
# 安装 dotnet 环境
# curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/qinglong/ray-dotnet-install.sh | bash /dev/stdin --no-official
curl -sSL https://ghproxy.com/https://raw.githubusercontent.com/RayWangQvQ/BiliBiliToolPro/main/qinglong/ray-dotnet-install.sh | bash /dev/stdin
-# 其他代码...
\ No newline at end of file
+# 安装需要用到的包
+pip3 install requests qrcode pillow
+# 其他代码...
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/QrCodeDto.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/QrCodeDto.cs
new file mode 100644
index 000000000..b89250338
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/QrCodeDto.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Passport
+{
+ public class QrCodeDto
+ {
+ public string Qrcode_key { get; set; }
+
+ public string Url { get; set; }
+ }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/TokenDto.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/TokenDto.cs
new file mode 100644
index 000000000..e8153df40
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Passport/TokenDto.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Passport
+{
+ public class TokenDto
+ {
+ public string Url { get; set; }
+ public string Refresh_token { get; set; }
+ public long Timestamp { get; set; }
+ public int Code { get; set; }
+ public string Message { get; set; }
+ }
+
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IPassportApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IPassportApi.cs
new file mode 100644
index 000000000..8ce564a70
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IPassportApi.cs
@@ -0,0 +1,17 @@
+using System.Threading.Tasks;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Passport;
+using WebApiClientCore.Attributes;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces
+{
+ [Header("Host", "passport.bilibili.com")]
+ public interface IPassportApi : IBiliBiliApi
+ {
+ [HttpGet("/x/passport-login/web/qrcode/generate")]
+ Task> GenerateQrCode();
+
+ [HttpGet("/x/passport-login/web/qrcode/poll?qrcode_key={qrcode_key}&source=main_mini")]
+ Task> CheckQrCodeHasScaned(string qrcode_key);
+ }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVideoApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVideoApi.cs
index 2651d4325..d86cd0d84 100644
--- a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVideoApi.cs
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVideoApi.cs
@@ -103,7 +103,7 @@ public interface IVideoWithoutCookieApi : IVideoApi
///
///
///
- [Header("Referer", "https://space.bilibili.com/")]
+ [Header("Referer", "https://www.bilibili.com/")]
[Header("Origin", "https://space.bilibili.com")]
[HttpGet("/x/space/arc/search?mid={upId}&ps={pageSize}&tid=0&pn={pageNumber}&keyword={keyword}&order=pubdate&jsonp=jsonp")]
Task> SearchVideosByUpId(long upId, int pageSize = 30, int pageNumber = 1, string keyword = "");
diff --git a/src/Ray.BiliBiliTool.Agent/BiliCookie.cs b/src/Ray.BiliBiliTool.Agent/BiliCookie.cs
index a8f9efea7..ab52c4ba6 100644
--- a/src/Ray.BiliBiliTool.Agent/BiliCookie.cs
+++ b/src/Ray.BiliBiliTool.Agent/BiliCookie.cs
@@ -1,14 +1,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
-using Microsoft.Extensions.Options;
+using Microsoft.Extensions.Logging.Abstractions;
using Ray.BiliBiliTool.Config;
-using Ray.BiliBiliTool.Config.Options;
using Ray.BiliBiliTool.Infrastructure;
namespace Ray.BiliBiliTool.Agent
@@ -35,8 +30,10 @@ public BiliCookie(ILogger logger,
{
SessData = sess;
}
+ }
- this.Check();
+ public BiliCookie(List ckList) : this(NullLogger.Instance,new CookieStrFactory(ckList))
+ {
}
[Description("DedeUserID")]
diff --git a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
index e7eaf0fd6..36d17512e 100644
--- a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
+++ b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
@@ -11,6 +11,7 @@
using Polly.Extensions.Http;
using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces;
using Ray.BiliBiliTool.Agent.HttpClientDelegatingHandlers;
+using Ray.BiliBiliTool.Agent.QingLong;
using Ray.BiliBiliTool.Config.Options;
using Ray.BiliBiliTool.Infrastructure;
@@ -69,6 +70,23 @@ public static IServiceCollection AddBiliBiliClientApi(this IServiceCollection se
services.AddBiliBiliClientApi("https://api.bilibili.com");
+ services.AddBiliBiliClientApi("http://passport.bilibili.com", false);
+
+ //qinglong
+ var qinglongHost = configuration["QL_URL"]?? "http://localhost:5600";
+ services
+ .AddHttpApi(o =>
+ {
+ o.HttpHost = new Uri(qinglongHost);
+ o.UseDefaultUserAgent = false;
+ })
+ .ConfigureHttpClient((sp, c) =>
+ {
+ c.DefaultRequestHeaders.Add("User-Agent",
+ sp.GetRequiredService>().CurrentValue.UserAgent);
+ })
+ .AddPolicyHandler(GetRetryPolicy());
+
return services;
}
diff --git a/src/Ray.BiliBiliTool.Agent/QingLong/IQingLongApi.cs b/src/Ray.BiliBiliTool.Agent/QingLong/IQingLongApi.cs
new file mode 100644
index 000000000..b8c579b7b
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/QingLong/IQingLongApi.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Ray.BiliBiliTool.Agent.Attributes;
+using WebApiClientCore.Attributes;
+
+namespace Ray.BiliBiliTool.Agent.QingLong
+{
+ [LogFilter]
+ public interface IQingLongApi
+ {
+ [HttpGet("/api/envs")]
+ Task>> GetEnvs(string searchValue, [Header("Authorization")] string token);
+
+ [HttpPost("/api/envs")]
+ Task>> AddEnvs([JsonContent] List envs, [Header("Authorization")] string token);
+
+ [HttpPut("/api/envs")]
+ Task> UpdateEnvs([JsonContent] UpdateQingLongEnv env, [Header("Authorization")] string token);
+ }
+
+ public class QingLongGenericResponse
+ {
+ public int Code { get; set; }
+
+ public T Data { get; set; }
+ }
+
+
+ public class QingLongEnv : UpdateQingLongEnv
+ {
+ public string timestamp { get; set; }
+ public int status { get; set; }
+ public long position { get; set; }
+ public DateTime createdAt { get; set; }
+ public DateTime updatedAt { get; set; }
+ }
+
+ public class AddQingLongEnv
+ {
+ public string value { get; set; }
+ public string name { get; set; }
+ public string remarks { get; set; }
+ }
+
+ public class UpdateQingLongEnv : AddQingLongEnv
+ {
+ public int id { get; set; }
+ }
+}
diff --git a/src/Ray.BiliBiliTool.Application.Contracts/ILoginTaskAppService.cs b/src/Ray.BiliBiliTool.Application.Contracts/ILoginTaskAppService.cs
new file mode 100644
index 000000000..6cdc8fb3b
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Application.Contracts/ILoginTaskAppService.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Text;
+
+namespace Ray.BiliBiliTool.Application.Contracts
+{
+ ///
+ /// 登录任务
+ ///
+ [Description("Login")]
+ public interface ILoginTaskAppService : IAppService
+ {
+ }
+}
diff --git a/src/Ray.BiliBiliTool.Application/LoginTaskAppService.cs b/src/Ray.BiliBiliTool.Application/LoginTaskAppService.cs
new file mode 100644
index 000000000..f2ab99620
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Application/LoginTaskAppService.cs
@@ -0,0 +1,378 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text.Json.Nodes;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.FileProviders;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using QRCoder;
+using Ray.BiliBiliTool.Agent;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces;
+using Ray.BiliBiliTool.Agent.QingLong;
+using Ray.BiliBiliTool.Application.Attributes;
+using Ray.BiliBiliTool.Application.Contracts;
+using Ray.BiliBiliTool.Infrastructure;
+using Ray.BiliBiliTool.Infrastructure.Enums;
+
+namespace Ray.BiliBiliTool.Application
+{
+ public class LoginTaskAppService : AppService, ILoginTaskAppService
+ {
+ private readonly ILogger _logger;
+ private readonly IPassportApi _passportApi;
+ private readonly IHostEnvironment _hostingEnvironment;
+ private readonly IQingLongApi _qingLongApi;
+ private readonly IConfiguration _configuration;
+
+ public LoginTaskAppService(
+ IConfiguration configuration,
+ ILogger logger,
+ IPassportApi passportApi,
+ IHostEnvironment hostingEnvironment,
+ IQingLongApi qingLongApi
+ )
+ {
+ _configuration = configuration;
+ _logger = logger;
+ _passportApi = passportApi;
+ _hostingEnvironment = hostingEnvironment;
+ _qingLongApi = qingLongApi;
+ }
+
+ [TaskInterceptor("扫码登录", TaskLevel.One)]
+ public override void DoTask()
+ {
+ //扫码登录
+ var suc = QrCodeLogin(out BiliCookie cookieInfo);
+ if (!suc) return;
+
+ var plateformType = _configuration.GetSection("PlateformType").Get();
+
+ //更新cookie到青龙env
+ if (plateformType == PlateformType.QingLong)
+ {
+ AddOrUpdateCkToQingLong(cookieInfo);
+ return;
+ }
+
+ //更新cookie到json
+ AddOrUpdateCkToJson(cookieInfo);
+ }
+
+ [TaskInterceptor("二维码登录", TaskLevel.Two)]
+ protected bool QrCodeLogin(out BiliCookie cookieInfo)
+ {
+ var result = false;
+ cookieInfo = new BiliCookie(new List() { "" });
+
+ var re = _passportApi.GenerateQrCode().Result;
+ if (re.Code != 0)
+ {
+ _logger.LogWarning("获取二维码失败:{msg}", re.ToJson());
+ return result;
+ }
+
+ var url = re.Data.Url;
+ GenerateQrCode(url);
+
+ var online = GetOnlinePic(url);
+ _logger.LogInformation(Environment.NewLine + Environment.NewLine);
+ _logger.LogInformation("如果上方二维码显示异常,或扫描失败,请使用浏览器访问如下链接,查看高清二维码:");
+ _logger.LogInformation(online + Environment.NewLine + Environment.NewLine);
+
+ var waitTimes = 10;
+ _logger.LogInformation("我数到{num},动作快点", waitTimes);
+ for (int i = 0; i < waitTimes; i++)
+ {
+ _logger.LogInformation("[{num}]等待扫描...", i + 1);
+
+ Task.Delay(5 * 1000).Wait();
+
+ var check = _passportApi.CheckQrCodeHasScaned(re.Data.Qrcode_key).Result;
+ if (check.Code != 0)
+ {
+ _logger.LogWarning("调用检查接口异常:{msg}", check.ToJson());
+ break;
+ }
+
+ if (check.Data.Code == 86038)//已失效
+ {
+ _logger.LogInformation(check.Data.Message);
+ break;
+ }
+
+ if (check.Data.Code == 0)
+ {
+ _logger.LogInformation("扫描成功!");
+ cookieInfo = GetCookie(check.Data.Url);
+ result = true;
+ break;
+ }
+
+ _logger.LogInformation("{msg}", check.Data.Message + Environment.NewLine);
+ }
+
+ return result;
+ }
+
+
+ [TaskInterceptor("添加ck到json配置文件", TaskLevel.Two)]
+ protected void AddOrUpdateCkToJson(BiliCookie ckInfo)
+ {
+ //读取json
+ var path = _hostingEnvironment.ContentRootPath;
+ var indexOfBin = path.LastIndexOf("bin");
+ if (indexOfBin != -1) path = path.Substring(0, indexOfBin);
+ var fileProvider = new PhysicalFileProvider(path);
+ IFileInfo fileInfo = fileProvider.GetFileInfo("cookies.json");
+ _logger.LogInformation("目标json地址:{path}", fileInfo.PhysicalPath);
+
+ if (!fileInfo.Exists)
+ {
+ using (var stream = File.Create(fileInfo.PhysicalPath))
+ {
+ using (var sw = new StreamWriter(stream))
+ {
+ sw.Write($"{{{Environment.NewLine}}}");
+ }
+ }
+ }
+
+ string json;
+ using (var stream = new FileStream(fileInfo.PhysicalPath, FileMode.Open))
+ {
+ using var reader = new StreamReader(stream);
+ json = reader.ReadToEnd();
+ }
+ var lines = json.Split(Environment.NewLine).ToList();
+
+ var indexOfCkConfigKey = lines.FindIndex(x => x.TrimStart().StartsWith("\"BiliBiliCookies\""));
+ if (indexOfCkConfigKey == -1)
+ {
+ _logger.LogInformation("未配置过cookie,初始化并新增");
+
+ var indexOfInsert = lines.FindIndex(x => x.TrimStart().StartsWith("{"));
+ lines.InsertRange(indexOfInsert + 1, new List()
+ {
+ " \"BiliBiliCookies\":[",
+ $@" ""{ckInfo.CookieStr}"",",
+ " ],"
+ });
+
+ SaveJson(lines, fileInfo);
+ _logger.LogInformation("新增成功!");
+ return;
+ }
+
+ ckInfo.CookieItemDictionary.TryGetValue("DedeUserID", out string userId);
+ userId ??= ckInfo.CookieStr;
+ var indexOfCkConfigEnd = lines.FindIndex(indexOfCkConfigKey, x => x.TrimStart().StartsWith("]"));
+ var indexOfTargetCk = lines.FindIndex(indexOfCkConfigKey,
+ indexOfCkConfigEnd - indexOfCkConfigKey,
+ x => x.Contains(userId) && !x.TrimStart().StartsWith("//"));
+
+ if (indexOfTargetCk == -1)
+ {
+ _logger.LogInformation("不存在该用户,新增cookie");
+ lines.Insert(indexOfCkConfigEnd, $@" ""{ckInfo.CookieStr}"",");
+ SaveJson(lines, fileInfo);
+ _logger.LogInformation("新增成功!");
+ return;
+ }
+
+ _logger.LogInformation("已存在该用户,更新cookie");
+ lines[indexOfTargetCk] = $@" ""{ckInfo.CookieStr}"",";
+ SaveJson(lines, fileInfo);
+ _logger.LogInformation("更新成功!");
+ }
+
+ [TaskInterceptor("添加ck到青龙环境变量", TaskLevel.Two)]
+ protected void AddOrUpdateCkToQingLong(BiliCookie ckInfo)
+ {
+ //拿token
+ var suc = GetToken(out string token);
+
+ if (!suc) return;
+
+ token = $"Bearer {token}";
+
+ //查env
+ var re = _qingLongApi.GetEnvs("Ray_BiliBiliCookies__", token).Result;
+
+ if (re.Code != 200)
+ {
+ _logger.LogInformation($"查询环境变量失败:{re}", re.ToJson());
+ return;
+ }
+
+ var list = re.Data.OrderBy(x => x.id);
+ QingLongEnv oldEnv = list.FirstOrDefault(x => x.value.Contains(ckInfo.UserId));
+
+ if (oldEnv != null)
+ {
+ _logger.LogInformation("用户已存在,更新cookie");
+ var update = new UpdateQingLongEnv()
+ {
+ id = oldEnv.id,
+ name = oldEnv.name,
+ value = ckInfo.CookieStr,
+ remarks = oldEnv.remarks,
+ };
+
+ var updateRe = _qingLongApi.UpdateEnvs(update, token).Result;
+ if (updateRe.Code == 200) _logger.LogInformation("更新成功!");
+ else _logger.LogInformation(updateRe.ToJson());
+
+ return;
+ }
+
+ _logger.LogInformation("用户不存在,新增cookie");
+ var lastNum = list.LastOrDefault()?.value.Split("__").LastOrDefault();
+ var newNum = int.Parse(lastNum ?? "-1") + 1;
+ var name = $"Ray_BiliBiliCookies__{newNum}";
+
+ var add = new AddQingLongEnv()
+ {
+ name = name,
+ value = ckInfo.CookieStr,
+ remarks = ""
+ };
+ var addRe = _qingLongApi.AddEnvs(new List() { add }, token).Result;
+ if (addRe.Code == 200) _logger.LogInformation("新增成功!");
+ else _logger.LogInformation(addRe.ToJson());
+
+ return;
+ }
+
+ private void GenerateQrCode(string str)
+ {
+ var qrGenerator = new QRCodeGenerator();
+ QRCodeData qrCodeData = qrGenerator.CreateQrCode(str, QRCodeGenerator.ECCLevel.L);
+
+ _logger.LogInformation("AsciiQRCode:");
+ //var qrCode = new AsciiQRCode(qrCodeData);
+ //var qrCodeStr = qrCode.GetGraphic(1, drawQuietZones: false);
+ //_logger.LogInformation(Environment.NewLine + qrCodeStr);
+
+ //Console.WriteLine("Console:");
+ //Print(qrCodeData);
+ PrintSmall(qrCodeData);
+ }
+
+ private void Print(QRCodeData qrCodeData)
+ {
+ Console.BackgroundColor = ConsoleColor.White;
+ for (int i = 0; i < qrCodeData.ModuleMatrix.Count + 2; i++) Console.Write(" ");//中文全角的空格符
+ Console.WriteLine();
+ for (int j = 0; j < qrCodeData.ModuleMatrix.Count; j++)
+ {
+ for (int i = 0; i < qrCodeData.ModuleMatrix.Count; i++)
+ {
+ //char charToPoint = qrCode.Matrix[i, j] ? '█' : ' ';
+ Console.Write(i == 0 ? " " : "");//中文全角的空格符
+ Console.BackgroundColor = qrCodeData.ModuleMatrix[i][j] ? ConsoleColor.Black : ConsoleColor.White;
+ Console.Write(' ');//中文全角的空格符
+ Console.BackgroundColor = ConsoleColor.White;
+ Console.Write(i == qrCodeData.ModuleMatrix.Count - 1 ? " " : "");//中文全角的空格符
+ }
+ Console.WriteLine();
+ }
+ for (int i = 0; i < qrCodeData.ModuleMatrix.Count + 2; i++) Console.Write(" ");//中文全角的空格符
+
+ Console.WriteLine();
+ }
+
+ private void PrintSmall(QRCodeData qrCodeData)
+ {
+ //黑黑(" ")
+ //白白("█")
+ //黑白("▄")
+ //白黑("▀")
+ var dic = new Dictionary()
+ {
+ {"11", ' '},
+ {"00", '█'},
+ {"10", '▄'},
+ {"01", '▀'},//todo:win平台的cmd会显示?,是已知问题,待想办法解决
+ //{"01", '^'},//▼▔
+ };
+
+ var count = qrCodeData.ModuleMatrix.Count;
+
+ var list = new List();
+ for (int rowNum = 0; rowNum < count; rowNum++)
+ {
+ var rowStr = "";
+ for (int colNum = 0; colNum < count; colNum++)
+ {
+ var num = qrCodeData.ModuleMatrix[colNum][rowNum] ? "1" : "0";
+ var numDown = "0";
+ if (rowNum + 1 < count)
+ numDown = qrCodeData.ModuleMatrix[colNum][rowNum + 1] ? "1" : "0";
+
+ rowStr += dic[num + numDown];
+ }
+ list.Add(rowStr);
+ rowNum++;
+ }
+
+ _logger.LogInformation(Environment.NewLine + string.Join(Environment.NewLine, list));
+ }
+
+ private string GetOnlinePic(string str)
+ {
+ var encode = System.Web.HttpUtility.UrlEncode(str); ;
+ return $"https://tool.lu/qrcode/basic.html?text={encode}";
+ }
+
+ private BiliCookie GetCookie(string url)
+ {
+ var ckItemList = url.Split('?')[1]
+ .Split("&gourl=")[0]
+ .Split('&')
+ .ToList();
+ var ckStr = string.Join(';', ckItemList);
+ var biliCk = new BiliCookie(new List() { ckStr });
+
+ biliCk.Check();
+ return biliCk;
+ }
+
+ private void SaveJson(List lines, IFileInfo fileInfo)
+ {
+ var newJson = string.Join(Environment.NewLine, lines);
+
+ using (var sw = new StreamWriter(fileInfo.PhysicalPath))
+ {
+ sw.Write(newJson);
+ }
+ }
+
+ #region qinglong
+
+ private bool GetToken(out string token)
+ {
+ token = "";
+
+ var qlDir = _configuration["QL_DIR"] ?? "/ql";
+ var authFile = Path.Combine(qlDir, "data/config/auth.json");
+
+ if (!File.Exists(authFile)) return false;
+
+ var authJson = File.ReadAllText(authFile);
+
+ var jb = JsonConvert.DeserializeObject(authJson);
+ token = jb["token"].ToString();
+
+ return true;
+ }
+
+ #endregion
+ }
+}
diff --git a/src/Ray.BiliBiliTool.Application/Ray.BiliBiliTool.Application.csproj b/src/Ray.BiliBiliTool.Application/Ray.BiliBiliTool.Application.csproj
index 9de70e91c..65607513b 100644
--- a/src/Ray.BiliBiliTool.Application/Ray.BiliBiliTool.Application.csproj
+++ b/src/Ray.BiliBiliTool.Application/Ray.BiliBiliTool.Application.csproj
@@ -6,8 +6,10 @@
+
+
diff --git a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
index d72123f42..e6aaa0064 100644
--- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
+++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
@@ -13,13 +13,15 @@ namespace Ray.BiliBiliTool.Config
///
public class EnvironmentVariablesExcludeEmptyConfigurationProvider : EnvironmentVariablesConfigurationProvider
{
+ private readonly bool _removeKeyPrefix;
private readonly string _prefix;
private readonly Func, bool> _startsWith;
private readonly Func, bool> _removeNullValue;
private readonly Func, bool> _fifter;
- public EnvironmentVariablesExcludeEmptyConfigurationProvider(string prefix = null) : base(prefix)
+ public EnvironmentVariablesExcludeEmptyConfigurationProvider(string prefix = null, bool removeKeyPrefix = true) : base(prefix)
{
+ _removeKeyPrefix = removeKeyPrefix;
_prefix = prefix ?? string.Empty;
_startsWith = c => c.Key.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
@@ -44,7 +46,7 @@ public override void Load()
///
private string NormalizeKey(string key)
{
- key = RemoveKeyPrefix(key);
+ if(_removeKeyPrefix) key = RemoveKeyPrefix(key);
key = ReplaceKeyDelimiter(key);
return key;
}
diff --git a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs
index 263c0bf6f..fea853940 100644
--- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs
+++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs
@@ -16,9 +16,11 @@ public class EnvironmentVariablesExcludeEmptyConfigurationSource : IConfiguratio
{
public string Prefix { get; set; }
+ public bool RemoveKeyPrefix { get; set; }
+
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
- return new EnvironmentVariablesExcludeEmptyConfigurationProvider(Prefix);
+ return new EnvironmentVariablesExcludeEmptyConfigurationProvider(Prefix, RemoveKeyPrefix);
}
}
}
diff --git a/src/Ray.BiliBiliTool.Config/Extensions/ConfigurationBuilderExtension.cs b/src/Ray.BiliBiliTool.Config/Extensions/ConfigurationBuilderExtension.cs
index 5264eba75..4271c1030 100644
--- a/src/Ray.BiliBiliTool.Config/Extensions/ConfigurationBuilderExtension.cs
+++ b/src/Ray.BiliBiliTool.Config/Extensions/ConfigurationBuilderExtension.cs
@@ -25,9 +25,10 @@ public static IConfigurationBuilder AddExcludeEmptyEnvironmentVariables(this ICo
/// The .
public static IConfigurationBuilder AddExcludeEmptyEnvironmentVariables(
this IConfigurationBuilder configurationBuilder,
- string prefix)
+ string prefix,
+ bool removeKeyPrefix = true)
{
- configurationBuilder.Add(new EnvironmentVariablesExcludeEmptyConfigurationSource { Prefix = prefix });
+ configurationBuilder.Add(new EnvironmentVariablesExcludeEmptyConfigurationSource { Prefix = prefix, RemoveKeyPrefix = removeKeyPrefix });
return configurationBuilder;
}
@@ -40,4 +41,4 @@ public static IConfigurationBuilder AddExcludeEmptyEnvironmentVariables(
public static IConfigurationBuilder AddExcludeEmptyEnvironmentVariables(this IConfigurationBuilder builder, Action configureSource)
=> builder.Add(configureSource);
}
-}
\ No newline at end of file
+}
diff --git a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
index 048e3b2f5..885022e72 100644
--- a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
+++ b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
@@ -20,6 +19,7 @@ public class BiliBiliToolHostedService : IHostedService
{
private readonly IHostApplicationLifetime _applicationLifetime;
private readonly IServiceProvider _serviceProvider;
+ private readonly IHostEnvironment _environment;
private readonly IConfiguration _configuration;
private readonly ILogger _logger;
private readonly CookieStrFactory _cookieStrFactory;
@@ -28,6 +28,7 @@ public class BiliBiliToolHostedService : IHostedService
public BiliBiliToolHostedService(
IHostApplicationLifetime applicationLifetime
, IServiceProvider serviceProvider
+ , IHostEnvironment environment
, IConfiguration configuration
, ILogger logger
, CookieStrFactory cookieStrFactory
@@ -35,6 +36,7 @@ IHostApplicationLifetime applicationLifetime
{
_applicationLifetime = applicationLifetime;
_serviceProvider = serviceProvider;
+ _environment = environment;
_configuration = configuration;
_logger = logger;
_cookieStrFactory = cookieStrFactory;
@@ -57,26 +59,34 @@ public Task StartAsync(CancellationToken cancellationToken)
var tasks = _configuration["RunTasks"]
.Split("&", options: StringSplitOptions.RemoveEmptyEntries);
- for (int i = 0; i < _cookieStrFactory.Count; i++)
+ if (tasks.Contains("Login"))
{
- _cookieStrFactory.CurrentNum = i + 1;
- _logger.LogInformation("######### 账号 {num} #########{newLine}", _cookieStrFactory.CurrentNum, Environment.NewLine);
+ DoTasks(tasks);
+ }
- try
+ else
+ {
+ for (int i = 0; i < _cookieStrFactory.Count; i++)
{
- DoTasks(tasks);
- if (isNotifySingle)
- {
- LogAppInfo();
+ _cookieStrFactory.CurrentNum = i + 1;
+ _logger.LogInformation("######### 账号 {num} #########{newLine}", _cookieStrFactory.CurrentNum, Environment.NewLine);
- var accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : "";
- _logger.LogInformation("·开始推送·{task}·{user}", $"{_configuration["RunTasks"]}任务", accountName);
+ try
+ {
+ DoTasks(tasks);
+ if (isNotifySingle)
+ {
+ LogAppInfo();
+
+ var accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : "";
+ _logger.LogInformation("·开始推送·{task}·{user}", $"{_configuration["RunTasks"]}任务", accountName);
+ }
+ }
+ catch (Exception e)
+ {
+ //ignore
+ _logger.LogWarning("异常:{msg}", e);
}
- }
- catch (Exception e)
- {
- //ignore
- _logger.LogWarning("异常:{msg}", e);
}
}
}
@@ -92,6 +102,9 @@ public Task StartAsync(CancellationToken cancellationToken)
LogAppInfo();
_logger.LogInformation("·开始推送·{task}·{user}", $"{_configuration["RunTasks"]}任务", "");
}
+ //环境
+ _logger.LogInformation("运行环境:{env}", _environment.EnvironmentName);
+ _logger.LogInformation("应用目录:{path}{newLine}", _environment.ContentRootPath, Environment.NewLine);
_logger.LogInformation("运行结束");
_applicationLifetime.StopApplication();
}
@@ -113,7 +126,7 @@ private bool PreCheck()
//Cookie
_logger.LogInformation("【账号个数】{count}个{newLine}", _cookieStrFactory.Count, Environment.NewLine);
- if (_cookieStrFactory.Count == 0) return false;
+ if (_cookieStrFactory.Count == 0 && !tasks.Contains("Login")) return false;
//是否跳过
if (_securityOptions.IsSkipDailyTask)
diff --git a/src/Ray.BiliBiliTool.Console/Program.cs b/src/Ray.BiliBiliTool.Console/Program.cs
index 4dbb96baf..bb649ddad 100644
--- a/src/Ray.BiliBiliTool.Console/Program.cs
+++ b/src/Ray.BiliBiliTool.Console/Program.cs
@@ -76,6 +76,7 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
}
//环境变量:
+ configurationBuilder.AddExcludeEmptyEnvironmentVariables("QL_", false);
configurationBuilder.AddExcludeEmptyEnvironmentVariables("Ray_");
//命令行:
@@ -85,6 +86,9 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
.GetSection("CommandLineMappings")
.Get>());
}
+
+ //本地cookie存储文件
+ configurationBuilder.AddJsonFile("cookies.json", true, true);
});
//日志:
diff --git a/src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj b/src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj
index 7b01192d7..cc6d544eb 100644
--- a/src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj
+++ b/src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj
@@ -90,6 +90,9 @@
PreserveNewest
+
+ PreserveNewest
+
diff --git a/src/Ray.BiliBiliTool.Console/appsettings.json b/src/Ray.BiliBiliTool.Console/appsettings.json
index a9103aac4..6ad77d850 100644
--- a/src/Ray.BiliBiliTool.Console/appsettings.json
+++ b/src/Ray.BiliBiliTool.Console/appsettings.json
@@ -1,7 +1,7 @@
{
//Cookie集合,取自浏览器,必填
"BiliBiliCookies": [ //Cookie字符串集合,登录bilibili后F12获取,形如"_uuid=abcd; buvid3=1234; sid=abc123"
- ""
+ "",
],
"RunTasks": "Daily", //要运行的任务名称[Daily,LiveLottery,UnfollowBatched,VipBigPoint,Test],多个使用&分隔,如“Daily&LiveLottery”,建议使用命令行参数指定
diff --git a/src/Ray.BiliBiliTool.Infrastructure/Cookie/CookieInfo.cs b/src/Ray.BiliBiliTool.Infrastructure/Cookie/CookieInfo.cs
index 0021ad57c..ff9e25ac5 100644
--- a/src/Ray.BiliBiliTool.Infrastructure/Cookie/CookieInfo.cs
+++ b/src/Ray.BiliBiliTool.Infrastructure/Cookie/CookieInfo.cs
@@ -26,6 +26,19 @@ public CookieInfo(string cookieStr)
}
}
+ public CookieInfo(List cookieItemList)
+ {
+ CookieItemList=cookieItemList ?? new List();
+ foreach (var item in CookieItemList)
+ {
+ var list = item.Split('=');
+ if (list.Length >= 2)
+ CookieItemDictionary.TryAdd(list[0].Trim(), list[1].Trim());
+ }
+
+ CookieStr = string.Join(';', CookieItemList);
+ }
+
public string CookieStr { get; set; }
public List CookieItemList { get; set; }
diff --git a/src/Ray.BiliBiliTool.Infrastructure/Enums/PlateformType.cs b/src/Ray.BiliBiliTool.Infrastructure/Enums/PlateformType.cs
index adac3bd13..47991555c 100644
--- a/src/Ray.BiliBiliTool.Infrastructure/Enums/PlateformType.cs
+++ b/src/Ray.BiliBiliTool.Infrastructure/Enums/PlateformType.cs
@@ -10,6 +10,7 @@ public enum PlateformType
{
Unknown,
GitHubActions,
- Docker
+ Docker,
+ QingLong
}
}