diff --git a/CHANGELOG.md b/CHANGELOG.md
index fc1962371..8c8d0f943 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -119,3 +119,5 @@
## 2.0.1
- PR[#539]:更新文档
- PR[#557]:修复直播接口权限不足问题
+## 2.0.2
+- PR[#617]:增加专栏投币功能与领取大会员经验的功能
diff --git a/common.props b/common.props
index 79e7c677e..74347ebbe 100644
--- a/common.props
+++ b/common.props
@@ -1,7 +1,7 @@
Ray
- 2.0.1
+ 2.0.2
$(NoWarn);CS1591;CS0436
diff --git a/docs/runInLocal.md b/docs/runInLocal.md
index 01564856f..e7d3ed0df 100644
--- a/docs/runInLocal.md
+++ b/docs/runInLocal.md
@@ -35,6 +35,7 @@ P.S.这里的运行环境指的是 `.NET Runtime 6.0.0` ,安装方法可详见
请下载 `win-x86-x64.zip`,此文件已自包含(self-contained)运行环境。
解压后,在应用目录打开cmd或powershell,执行`.\Ray.BiliBiliTool.Console.exe --runTasks=Login`,扫码登录。
+也可以直接双击`Ray.BiliBiliTool.Console.exe`来运行,建议使用windows自带的定时任务来执行它
## 3. Linux:
diff --git a/krew/.gitignore b/krew/.gitignore
new file mode 100644
index 000000000..45f4d8132
--- /dev/null
+++ b/krew/.gitignore
@@ -0,0 +1,2 @@
+bin
+bilipro
\ No newline at end of file
diff --git a/krew/Makefile b/krew/Makefile
index b18791ada..23f9d3c1f 100644
--- a/krew/Makefile
+++ b/krew/Makefile
@@ -20,18 +20,30 @@ help: #### display help
deploy: build install #### build + install
+.PHONY: fmt
+fmt: #### run go fmt against code
+ @go fmt ./...
+
+
+.PHONY: vet
+vet: #### run go vet against code
+ @go vet ./...
+
+.PHONY: update-modules
+update-modules: tidy #### update go modules
+
+.PHONY: tidy
+tidy: #### run go mod tidy
+ @go mod tidy
+
.PHONY: build
build: #### build the plugin
- @go vet ./... && \
- go fmt ./... && \
- echo "build on ${GOOS}/${GOARCH}" && \
- 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
-
+ @echo "build on ${GOOS}/${GOARCH}" && \
+ GOOS=${GOOS} GOARCH=${GOARCH} CGO_ENABLED=0 go build -mod readonly -ldflags "-X github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd.version=${GITCOMMIT}" -o bin/$(BIN_NAME) cmd/kubectl-bilipro.go
.PHONY: install
install: #### install the plugin
- @cd ${ROOT_DIR}/krew/cmd && \
+ @cd ${ROOT_DIR}/krew/bin && \
sudo install ./$(BIN_NAME) ${KUBECTL_DIR}/$(BIN_NAME)
.PHONY: test
diff --git a/krew/README.md b/krew/README.md
index f56318963..36697df11 100644
--- a/krew/README.md
+++ b/krew/README.md
@@ -18,15 +18,18 @@ For example: the kubectl is installed under `/usr/bin`, then put the bilibilipro
### Deployment && Update
-Command: `kubectl bilipro init --config config.yaml [optional]--login`
+Prerequsites: please make sure you have the right permission to at least manage namespaces/deployments
+
+Command: `kubectl bilipro init --config config.yaml`
Creates Deployment with the needed environments.
Optional Options:
-- `--image=zai7lou/bilibili_tool_pro:1.0.1`
+- `--image=zai7lou/bilibili_tool_pro:2.0.1`
- `--namespace=bilipro`
-- `--image-pull-secret=`
+- `--image-pull-secret=`
+- `--login` to scan QR code to login
Required Options:
diff --git a/krew/cmd/kubectl-bilipro.go b/krew/cmd/kubectl-bilipro.go
index f9e3ca6ea..55256366e 100644
--- a/krew/cmd/kubectl-bilipro.go
+++ b/krew/cmd/kubectl-bilipro.go
@@ -1,6 +1,7 @@
package main
import (
+ "fmt"
"os"
"github.com/spf13/pflag"
@@ -8,7 +9,6 @@ import (
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/cmd"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"k8s.io/cli-runtime/pkg/genericclioptions"
- "k8s.io/klog/v2"
)
func main() {
@@ -17,7 +17,7 @@ func main() {
cmd := cmd.NewExecutor(genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr})
if err := cmd.Execute(); err != nil {
- klog.Error(helper.GenErrorMsg(helper.SERVER_ERROR, err.Error()).Error())
+ fmt.Println(helper.GenErrorMsg(helper.SERVER_ERROR, err.Error()).Error())
os.Exit(1)
}
}
diff --git a/krew/go.mod b/krew/go.mod
index 37d7d67a8..9f7fd48fa 100644
--- a/krew/go.mod
+++ b/krew/go.mod
@@ -9,7 +9,6 @@ require (
k8s.io/apimachinery v0.25.4
k8s.io/cli-runtime v0.25.4
k8s.io/client-go v0.25.4
- k8s.io/klog/v2 v2.80.1
sigs.k8s.io/kustomize/api v0.12.1
sigs.k8s.io/kustomize/kyaml v0.13.9
sigs.k8s.io/yaml v1.3.0
@@ -58,10 +57,11 @@ require (
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/klog/v2 v2.80.1 // indirect
k8s.io/kube-openapi v0.0.0-20221012153701-172d655c2280 // indirect
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d // 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
+// replace github.com/RayWangQvQ/BiliBiliToolPro/krew => ../krew
diff --git a/krew/pkg/cmd/delete.go b/krew/pkg/cmd/delete.go
index 9acbdf5f4..a291d4e27 100644
--- a/krew/pkg/cmd/delete.go
+++ b/krew/pkg/cmd/delete.go
@@ -1,6 +1,7 @@
package cmd
import (
+ "fmt"
"io"
"os/exec"
"strings"
@@ -9,8 +10,6 @@ import (
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
- "k8s.io/klog/v2"
-
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"github.com/spf13/cobra"
@@ -42,9 +41,10 @@ func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command {
err := o.run(out)
if err != nil {
- klog.Error(err)
+ fmt.Println(err)
return err
}
+ fmt.Println("bilibili tool is removed from your cluster")
return nil
},
}
diff --git a/krew/pkg/cmd/get.go b/krew/pkg/cmd/get.go
index 162538ec0..15744cb20 100644
--- a/krew/pkg/cmd/get.go
+++ b/krew/pkg/cmd/get.go
@@ -1,11 +1,10 @@
package cmd
import (
+ "fmt"
"io"
"os/exec"
- "k8s.io/klog/v2"
-
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"github.com/spf13/cobra"
@@ -37,7 +36,7 @@ func newGetCmd(out io.Writer, errOut io.Writer) *cobra.Command {
err := o.run(out)
if err != nil {
- klog.Error(err)
+ fmt.Println(err)
return err
}
return nil
diff --git a/krew/pkg/cmd/init.go b/krew/pkg/cmd/init.go
index 21a80cf51..3a1f5ccd4 100644
--- a/krew/pkg/cmd/init.go
+++ b/krew/pkg/cmd/init.go
@@ -7,7 +7,6 @@ import (
"os"
"os/exec"
"strings"
- "time"
corev1 "k8s.io/api/core/v1"
@@ -17,8 +16,6 @@ import (
"sigs.k8s.io/kustomize/api/types"
- "k8s.io/klog/v2"
-
"github.com/spf13/cobra"
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
@@ -52,7 +49,7 @@ func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run(out)
if err != nil {
- klog.Error(err)
+ fmt.Println(err)
return err
}
return nil
@@ -60,7 +57,7 @@ func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command {
}
f := cmd.Flags()
- f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:1.0.1", "bilibilipro image")
+ f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:2.0.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")
@@ -94,6 +91,8 @@ func (o *initCmd) run(writer io.Writer) error {
}
// TODO: All about paths are a little bit tricky should give it more thoughts
+
+ fmt.Println("Creating the kustomization file")
// if the bilibili tool is deployed under system/pre-defined namespace, ignore the namespace file
var resources []string // nolint: go-staticcheck
if o.deployOpts.Namespace == "default" || o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
@@ -211,6 +210,7 @@ func (o *initCmd) run(writer io.Writer) error {
}
}
+ fmt.Println("Applying the kustomization file")
// do kubectl apply
// make sure kubectl is under your PATH
cmd := exec.Command("kubectl", "apply", "-f", "-")
@@ -219,9 +219,9 @@ func (o *initCmd) run(writer io.Writer) error {
return err
}
- // if there is login required
+ // if there is login required, exectue the login command as the last step
if o.login {
-
+ fmt.Println("please login...")
client, _, err := helper.GetK8sClient()
if err != nil {
return err
@@ -233,8 +233,33 @@ func (o *initCmd) run(writer io.Writer) error {
return err
}
- // TODO: Stupid way, just sleep to wait container is ready, maybe a watch is a better option
- time.Sleep(15 * time.Second)
+ fmt.Println("wait for the deployment to be ready")
+ // Wait for the deployment ready
+ checkCmdArgs := []string{
+ "rollout",
+ "status",
+ "deployment/bilibilipro",
+ "-n",
+ o.deployOpts.Namespace,
+ }
+ checkCmd := exec.Command("kubectl", checkCmdArgs...)
+
+ for {
+ if err := checkCmd.Start(); err != nil {
+ fmt.Printf("deployment is not ready yet, current status: %v\n", err)
+ continue
+ }
+
+ err := checkCmd.Wait()
+ if err == nil {
+ fmt.Printf("deployment is ready\n")
+ break
+ }
+ fmt.Printf("deployment is not ready yet, current status: %v\n", err)
+ }
+
+ fmt.Println("please scan the QR code")
+ // Exec the login command
args := []string{
"exec",
podName,
diff --git a/krew/pkg/cmd/version.go b/krew/pkg/cmd/version.go
index 6a7b43f30..d0c85d860 100644
--- a/krew/pkg/cmd/version.go
+++ b/krew/pkg/cmd/version.go
@@ -4,8 +4,6 @@ import (
"fmt"
"io"
- "k8s.io/klog/v2"
-
"github.com/spf13/cobra"
)
@@ -35,7 +33,7 @@ func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command {
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run()
if err != nil {
- klog.Error(err)
+ fmt.Println(err)
return err
}
return nil
diff --git a/krew/pkg/resources/base/bilibiliPro/deployment.yaml b/krew/pkg/resources/base/bilibiliPro/deployment.yaml
index 7ec6d1343..97b8d89a3 100644
--- a/krew/pkg/resources/base/bilibiliPro/deployment.yaml
+++ b/krew/pkg/resources/base/bilibiliPro/deployment.yaml
@@ -13,7 +13,7 @@ spec:
spec:
containers:
- name: bilibilipro
- image: zai7lou/bilibili_tool_pro:1.0.1
+ image: zai7lou/bilibili_tool_pro:2.0.1
imagePullPolicy: IfNotPresent
resources:
requests:
diff --git a/krew/pkg/utils/client.go b/krew/pkg/utils/client.go
index 7a220867b..81f058736 100644
--- a/krew/pkg/utils/client.go
+++ b/krew/pkg/utils/client.go
@@ -33,6 +33,8 @@ func GetK8sClient() (*kubernetes.Clientset, *rest.Config, error) {
if err != nil {
return nil, nil, GenErrorMsg(SERVER_ERROR, err.Error())
}
+ config.QPS = float32(10.0)
+ config.Burst = 20
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
diff --git a/scripts/publish.ps1 b/scripts/publish.ps1
new file mode 100644
index 000000000..e21417b8c
--- /dev/null
+++ b/scripts/publish.ps1
@@ -0,0 +1,16 @@
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-x86 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-x86
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-x64
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime win-arm64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/win-arm64
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-x64
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-musl-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-musl-x64
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-arm64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-arm64
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime linux-arm --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/linux-arm
+dotnet.exe publish ../src/Ray.BiliBiliTool.Console/Ray.BiliBiliTool.Console.csproj --runtime osx-x64 --no-self-contained -c Release -p:PublishSingleFile=true -o ./bin/Publish/osx-x64
+Remove-Item ./bin/Publish/win-x86/*.pdb
+Remove-Item ./bin/Publish/win-x64/*.pdb
+Remove-Item ./bin/Publish/win-arm64/*.pdb
+Remove-Item ./bin/Publish/linux-x64/*.pdb
+Remove-Item ./bin/Publish/linux-musl-x64/*.pdb
+Remove-Item ./bin/Publish/linux-arm64/*.pdb
+Remove-Item ./bin/Publish/linux-arm/*.pdb
+Remove-Item ./bin/Publish/osx-x64/*.pdb
diff --git a/scripts/publish.sh b/scripts/publish.sh
index 22ef74fcd..74811d8e7 100644
--- a/scripts/publish.sh
+++ b/scripts/publish.sh
@@ -62,11 +62,10 @@ publish_dotnet_dependent() {
dotnet publish --configuration Release \
--self-contained false \
-p:PublishSingleFile=true \
+ -p:DebugType=None \
+ -p:DebugSymbols=false \
-o $outputDir
- echo "clear pdb files"
- rm -rf $outputDir/*.pdb
-
echo "zip files..."
cd $publishDir
zip -q -r bilibili-tool-pro-v$version-dotnet-dependent.zip ./dotnet-dependent/*
@@ -90,11 +89,10 @@ publish_self_contained() {
--runtime $runtime \
-p:PublishTrimmed=true \
-p:PublishSingleFile=true \
+ -p:DebugType=None \
+ -p:DebugSymbols=false \
-o $outputDir
- echo "clear pdb files"
- rm -rf $outputDir/*.pdb
-
echo "zip files..."
cd $publishDir
zip -q -r bilibili-tool-pro-v$version-$runtime.zip ./$runtime/*
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs
new file mode 100644
index 000000000..7fd3f3e9d
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/AddCoinForArticleRequest.cs
@@ -0,0 +1,22 @@
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+
+public class AddCoinForArticleRequest
+{
+ public AddCoinForArticleRequest(long cvid,long mid,string csrf)
+ {
+ Aid = cvid;
+ Upid = mid;
+ Csrf = csrf;
+ }
+
+ public long Aid { get; set; }
+
+ public long Upid { get; set; }
+
+ public int Multiply { get; set; } = 1;
+
+ // 必须为2
+ public int Avtype { get; private set; } = 2;
+
+ public string Csrf { get; set; }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs
new file mode 100644
index 000000000..22b9b37a6
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticleInfoResponse.cs
@@ -0,0 +1,10 @@
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+
+public class SearchArticleInfoResponse
+{
+ public int Like { get; set; }
+
+ public int Coin { get; set; }
+
+ public long Mid { get; set; }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs
new file mode 100644
index 000000000..e4cae3b9b
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchArticlesByUpIdFullFto.cs
@@ -0,0 +1,19 @@
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+
+public class SearchArticlesByUpIdDto
+{
+ public long Mid { get; set; }
+
+ public int Pn { get; set; } = 1;
+
+ public int Ps { get; set; } = 30;
+
+ public string Sort { get; set; } = "publish_time";
+}
+
+public class SearchArticlesByUpIdFullDto : SearchArticlesByUpIdDto
+{
+ public string w_rid { get; set; }
+
+ public long wts { get; set; }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs
new file mode 100644
index 000000000..bef59b449
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/Article/SearchUpArticlesResponse.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+
+public class SearchUpArticlesResponse
+{
+ public List Articles { get; set; }
+ public int Count { get; set; }
+
+}
+
+public class ArticleInfo
+{
+ public long Id { get; set; }
+
+ public string Title { get; set; }
+
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs
new file mode 100644
index 000000000..542e6b083
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VipExperienceRequest.cs
@@ -0,0 +1,6 @@
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask;
+
+public class VipExperienceRequest
+{
+ public string csrf { get; set; }
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs
new file mode 100644
index 000000000..ae85e0fd8
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Dtos/VipTask/VouchersInfoResponse.cs
@@ -0,0 +1,28 @@
+using System.Collections.Generic;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask;
+
+public class VouchersInfoResponse
+{
+ public List List { get; set; }
+ public bool IsShortVip { get; set; }
+ public bool IsFreightOpen { get; set; }
+ public int Level { get; set; }
+ public int CurExp { get; set; }
+ public int NextExp { get; set; }
+ public bool IsVip { get; set; }
+ public int IsSeniorMember { get; set; }
+ public int Format060102 { get; set; }
+}
+
+
+public class List
+{
+ public int Type { get; set; }
+ public int State { get; set; }
+ public int ExpireTime { get; set; }
+ public int VipType { get; set; }
+ public int NextReceiveDays { get; set; }
+ public int PeriodEndUnix { get; set; }
+}
+
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs
new file mode 100644
index 000000000..2019bb33b
--- /dev/null
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IArticleApi.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Video;
+using WebApiClientCore.Attributes;
+
+namespace Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces
+{
+
+ [Header("Host", "api.bilibili.com")]
+ public interface IArticleApi : IBiliBiliApi
+ {
+ [Header("Content-Type", "application/x-www-form-urlencoded")]
+ [Header("Origin", "https://www.bilibili.com")]
+ [HttpPost("/x/web-interface/coin/add")]
+ Task AddCoinForArticle([FormContent] AddCoinForArticleRequest request, [Header("referer")] string refer = "https://www.bilibili.com/read/cv5806746/?from=search&spm_id_from=333.337.0.0");
+
+
+ [Header("Referer", "https://www.bilibili.com/")]
+ [Header("Origin", "https://space.bilibili.com")]
+ [HttpGet("/x/space/wbi/article")]
+ Task> SearchUpArticlesByUpId(
+ [PathQuery] SearchArticlesByUpIdFullDto request);
+
+ ///
+ /// 获取专栏详情
+ ///
+ ///
+ ///
+ [HttpGet("/x/article/viewinfo?id={cvid}")]
+ Task> SearchArticleInfo(long cvid);
+
+
+ [Header("Content-Type", "application/x-www-form-urlencoded")]
+ [Header("Referer", "https://www.bilibili.com/read/cv{cvid}/?from=search&spm_id_from=333.337.0.0")]
+ [Header("Origin", "https://www.bilibili.com")]
+ [HttpPost("/x/article/like?id={cvid}&type=1&csrf={csrf}")]
+ Task Like(long cvid, string csrf);
+
+ }
+
+
+}
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs
index 903d5405c..7a851b2de 100644
--- a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IMangaApi.cs
@@ -26,8 +26,8 @@ public interface IMangaApi : IBiliBiliApi
///
///
///
- [HttpPost("/twirp/bookshelf.v1.Bookshelf/AddHistory?platform={platform}&comic_id=27355&ep_id=381662")]
- Task ReadManga(string platform);
+ [HttpPost("/twirp/bookshelf.v1.Bookshelf/AddHistory?platform={platform}&comic_id={comic_id}&ep_id={ep_id}")]
+ Task ReadManga(string platform, long comic_id, long ep_id);
///
/// 获取会员漫画奖励
diff --git a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs
index ecc0451da..f83122d74 100644
--- a/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs
+++ b/src/Ray.BiliBiliTool.Agent/BiliBiliAgent/Interfaces/IVipBigPointApi.cs
@@ -31,5 +31,12 @@ public interface IVipBigPointApi
[HttpPost("/pgc/activity/deliver/task/complete")]
Task ViewComplete([FormContent] ViewRequest request);
+
+ [HttpGet("/x/vip/privilege/my")]
+ Task> GetVouchersInfo();
+
+ [Header("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")]
+ [HttpPost("/x/vip/experience/add")]
+ Task GetVipExperience([FormContent] VipExperienceRequest request);
}
}
diff --git a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
index 64558e390..92b8831c4 100644
--- a/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
+++ b/src/Ray.BiliBiliTool.Agent/Extensions/ServiceCollectionExtension.cs
@@ -73,6 +73,9 @@ public static IServiceCollection AddBiliBiliClientApi(this IServiceCollection se
services.AddBiliBiliClientApi("https://live-trace.bilibili.com");
services.AddBiliBiliClientApi("https://www.bilibili.com", false);
+ // 添加注入
+ services.AddBiliBiliClientApi("https://api.bilibili.com");
+
//qinglong
var qinglongHost = configuration["QL_URL"] ?? "http://localhost:5600";
services
diff --git a/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs b/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs
index abd10b07f..f78097ef3 100644
--- a/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs
+++ b/src/Ray.BiliBiliTool.Application.Contracts/IVipBigPointAppService.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
+using System.Threading.Tasks;
namespace Ray.BiliBiliTool.Application.Contracts
{
@@ -12,5 +13,6 @@ namespace Ray.BiliBiliTool.Application.Contracts
public interface IVipBigPointAppService : IAppService
{
+ Task VipExpress();
}
}
diff --git a/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs b/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs
index 6f82e6d59..db2ee02f9 100644
--- a/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs
+++ b/src/Ray.BiliBiliTool.Application/DailyTaskAppService.cs
@@ -23,6 +23,7 @@ public class DailyTaskAppService : AppService, IDailyTaskAppService
private readonly ILogger _logger;
private readonly IAccountDomainService _accountDomainService;
private readonly IVideoDomainService _videoDomainService;
+ private readonly IArticleDomainService _articleDomainService;
private readonly IDonateCoinDomainService _donateCoinDomainService;
private readonly IMangaDomainService _mangaDomainService;
private readonly ILiveDomainService _liveDomainService;
@@ -41,6 +42,7 @@ public DailyTaskAppService(
IOptionsMonitor> dicOptions,
IAccountDomainService accountDomainService,
IVideoDomainService videoDomainService,
+ IArticleDomainService articleDomainService,
IDonateCoinDomainService donateCoinDomainService,
IMangaDomainService mangaDomainService,
ILiveDomainService liveDomainService,
@@ -56,6 +58,7 @@ public DailyTaskAppService(
_expDic = dicOptions.Get(Constants.OptionsNames.ExpDictionaryName);
_accountDomainService = accountDomainService;
_videoDomainService = videoDomainService;
+ _articleDomainService = articleDomainService;
_donateCoinDomainService = donateCoinDomainService;
_mangaDomainService = mangaDomainService;
_liveDomainService = liveDomainService;
@@ -79,7 +82,8 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken)
DailyTaskInfo dailyTaskInfo = await GetDailyTaskStatus();
await WatchAndShareVideo(dailyTaskInfo);
- await AddCoinsForVideo(userInfo);
+
+ await AddCoins(userInfo);
//签到:
await LiveSign();
@@ -91,6 +95,9 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken)
await ReceiveVipPrivilege(userInfo);
await ReceiveMangaVipReward(userInfo);
+ //TODO 大会员领经验
+
+
await Charge(userInfo);
}
@@ -124,7 +131,7 @@ protected async Task SetCookiesAsync(BiliCookie biliCookie, Cancella
private async Task Login()
{
UserInfo userInfo = await _accountDomainService.LoginByCookie();
- if (userInfo == null) throw new Exception("登录失败,请检查Cookie");//终止流程
+ if (userInfo == null) throw new Exception("登录失败,请检查Cookie"); //终止流程
_expDic.TryGetValue("每日登录", out int exp);
_logger.LogInformation("登录成功,经验+{exp} √", exp);
@@ -153,6 +160,7 @@ private async Task WatchAndShareVideo(DailyTaskInfo dailyTaskInfo)
_logger.LogInformation("已配置为关闭,跳过任务");
return;
}
+
await _videoDomainService.WatchAndShareVideo(dailyTaskInfo);
}
@@ -160,14 +168,28 @@ private async Task WatchAndShareVideo(DailyTaskInfo dailyTaskInfo)
/// 投币任务
///
[TaskInterceptor("投币", rethrowWhenException: false)]
- private async Task AddCoinsForVideo(UserInfo userInfo)
+ private async Task AddCoins(UserInfo userInfo)
{
if (_dailyTaskOptions.SaveCoinsWhenLv6 && userInfo.Level_info.Current_level >= 6)
{
_logger.LogInformation("已经为LV6大佬,开始白嫖");
return;
}
- await _donateCoinDomainService.AddCoinsForVideos();
+
+ if (_dailyTaskOptions.IsDonateCoinForArticle)
+ {
+ _logger.LogInformation("专栏投币已开启");
+
+ if (!await _articleDomainService.AddCoinForArticles())
+ {
+ _logger.LogInformation("专栏投币结束,转入视频投币");
+ await _donateCoinDomainService.AddCoinsForVideos();
+ }
+ }
+ else
+ {
+ await _donateCoinDomainService.AddCoinsForVideos();
+ }
}
///
diff --git a/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs b/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs
index fd7a8c197..7d3d038ee 100644
--- a/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs
+++ b/src/Ray.BiliBiliTool.Application/VipBigPointAppService.cs
@@ -4,6 +4,7 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
+using Ray.BiliBiliTool.Agent;
using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos;
using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask;
using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces;
@@ -19,23 +20,81 @@ public class VipBigPointAppService : AppService, IVipBigPointAppService
private readonly IConfiguration _configuration;
private readonly IVipBigPointApi _vipApi;
private readonly IAccountDomainService _loginDomainService;
+ private readonly IVideoDomainService _videoDomainService;
+ private readonly IAccountDomainService _accountDomainService;
+ private readonly BiliCookie _biliCookie;
public VipBigPointAppService(
IConfiguration configuration,
ILogger logger,
IVipBigPointApi vipApi,
- IAccountDomainService loginDomainService
- )
+ IAccountDomainService loginDomainService,
+ IVideoDomainService videoDomainService,
+ BiliCookie biliCookie, IAccountDomainService accountDomainService)
{
_configuration = configuration;
_logger = logger;
_vipApi = vipApi;
_loginDomainService = loginDomainService;
+ _videoDomainService = videoDomainService;
+ _biliCookie = biliCookie;
+ _accountDomainService = accountDomainService;
}
+ public async Task VipExpress()
+ {
+ _logger.LogInformation("大会员经验领取任务开始");
+ var re = await _vipApi.GetVouchersInfo();
+ if (re.Code == 0)
+ {
+ var state = re.Data.List.Find(x => x.Type == 9).State;
+
+ switch (state)
+ {
+ case 2:
+ _logger.LogInformation("大会员经验观看任务未完成");
+ _logger.LogInformation("开始观看视频");
+ // 观看视频,暂时没有好办法解决,先这样使着
+ DailyTaskInfo dailyTaskInfo = await _accountDomainService.GetDailyTaskStatus();
+ await _videoDomainService.WatchAndShareVideo(dailyTaskInfo);
+ // 跳转到未兑换,执行兑换任务
+ goto case 0;
+
+ case 1:
+ _logger.LogInformation("大会员经验已兑换");
+ break;
+
+ case 0:
+ _logger.LogInformation("大会员经验未兑换");
+ //兑换api
+ var response = await _vipApi.GetVipExperience(new VipExperienceRequest()
+ {
+ csrf = _biliCookie.BiliJct
+ });
+ if (response.Code != 0)
+ {
+ _logger.LogInformation("大会员经验领取失败,错误信息:{message}", response.Message);
+ break;
+ }
+ _logger.LogInformation("领取成功,经验+10 √");
+ break;
+
+ default:
+ _logger.LogDebug("大会员经验领取失败,未知错误");
+ break;
+ }
+
+ }
+
+ }
+
+
[TaskInterceptor("大会员大积分", TaskLevel.One)]
public override async Task DoTaskAsync(CancellationToken cancellationToken)
{
+ await VipExpress();
+
+ // TODO 解决taskInfo在一个任务出错后,后续的任务均会报空引用错误
var ui = await GetUserInfo();
if (ui.GetVipType() == VipType.None)
@@ -66,7 +125,7 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken)
taskInfo = await ViewAnimate(taskInfo);
//浏览影视频道页10秒
- taskInfo = await ViewFilmChannel(taskInfo);
+ // taskInfo = await ViewFilmChannel(taskInfo);
//浏览会员购页面10秒
taskInfo = ViewVipMall(taskInfo);
@@ -76,10 +135,12 @@ public override async Task DoTaskAsync(CancellationToken cancellationToken)
//领取购买任务
taskInfo = await BuyVipVideo(taskInfo);
- taskInfo = await BuyVipProduct(taskInfo);
+ // taskInfo = await BuyVipProduct(taskInfo);
taskInfo = await BuyVipMall(taskInfo);
-
+
taskInfo.LogInfo(_logger);
+
+
}
[TaskInterceptor("测试Cookie")]
diff --git a/src/Ray.BiliBiliTool.Config/Constants.cs b/src/Ray.BiliBiliTool.Config/Constants.cs
index 870682bbe..cc6448cd8 100644
--- a/src/Ray.BiliBiliTool.Config/Constants.cs
+++ b/src/Ray.BiliBiliTool.Config/Constants.cs
@@ -1,5 +1,4 @@
-
-using System.Collections;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
@@ -35,26 +34,30 @@ public static class OptionsNames
///
public static Dictionary GetExpDic()
{
- var dic = new Dictionary()
+ Dictionary dic = new()
{
{"每日登录", "5"},
{"每日观看视频", "5"},
{"每日分享视频", "5"},
{"每日投币", "10"}
};
+
+ string buildKey(string key) => $"{OptionsNames.ExpDictionaryName}:{key}";
+
return dic.Select(x =>
- new KeyValuePair($"{OptionsNames.ExpDictionaryName}:{x.Key}", x.Value))
+ new KeyValuePair(buildKey(x.Key), x.Value))
.ToDictionary(k => k.Key, v => v.Value);
}
///
- /// 投币接口的data.code返回以下这些状态码,则可以继续尝试投币
- /// 如返回除这些之外的状态码,则终止投币流程,不进行无意义的尝试(比如返回-101:账号未登录;-102:账号被封停;-111:csrf校验失败等)
+ /// 投币接口的data.code返回以下这些状态码,则可以继续尝试投币
+ /// 如返回除这些之外的状态码,则终止投币流程,不进行无意义的尝试
+ /// (比如返回-101:账号未登录;-102:账号被封停;-111:csrf校验失败等)
///
///
public static Dictionary GetDonateCoinCanContinueStatusDic()
{
- var dic = new Dictionary()
+ Dictionary dic = new()
{
{"0", "成功"},
{"-400", "请求错误"},
@@ -64,8 +67,11 @@ public static Dictionary GetDonateCoinCanContinueStatusDic()
{"34004", "投币间隔太短"},
{"34005", "超过投币上限"}
};
+
+ string buildKey(string key) => $"{OptionsNames.DonateCoinCanContinueStatusDictionaryName}:{key}";
+
return dic.Select(x =>
- new KeyValuePair($"{OptionsNames.DonateCoinCanContinueStatusDictionaryName}:{x.Key}", x.Value))
+ new KeyValuePair(buildKey(x.Key), x.Value))
.ToDictionary(k => k.Key, v => v.Value)
;
}
@@ -81,6 +87,7 @@ public static Dictionary GetCommandLineMappingsDic()
{"--randomSleep","Security:RandomSleepMaxMin"},
{"--numberOfCoins", "DailyTaskConfig:NumberOfCoins"},
+ {"--numberOfProtectedCoins", "DailyTaskConfig:NumberOfProtectedCoins"},
{"--saveCoinsWhenLv6", "DailyTaskConfig:SaveCoinsWhenLv6"},
{"--selectLike", "DailyTaskConfig:SelectLike"},
{"--supportUpIds", "DailyTaskConfig:SupportUpIds"},
diff --git a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
index e6aaa0064..61dec6a96 100644
--- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
+++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationProvider.cs
@@ -8,7 +8,7 @@
namespace Ray.BiliBiliTool.Config
{
///
- /// 自定义的排除空值的环境变量提供者
+ /// 自定义的排除空值的环境变量提供者
/// (使用GitHub Actions的脚本传入环境变量,空值会保留,所以这里自己写了一个用来替换掉默认的)
///
public class EnvironmentVariablesExcludeEmptyConfigurationProvider : EnvironmentVariablesConfigurationProvider
@@ -19,7 +19,10 @@ public class EnvironmentVariablesExcludeEmptyConfigurationProvider : Environment
private readonly Func, bool> _removeNullValue;
private readonly Func, bool> _fifter;
- public EnvironmentVariablesExcludeEmptyConfigurationProvider(string prefix = null, bool removeKeyPrefix = true) : base(prefix)
+ public EnvironmentVariablesExcludeEmptyConfigurationProvider(
+ string prefix = null,
+ bool removeKeyPrefix = true)
+ : base(prefix)
{
_removeKeyPrefix = removeKeyPrefix;
_prefix = prefix ?? string.Empty;
@@ -46,7 +49,8 @@ public override void Load()
///
private string NormalizeKey(string key)
{
- if(_removeKeyPrefix) 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 fea853940..4d553edfc 100644
--- a/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs
+++ b/src/Ray.BiliBiliTool.Config/EnvironmentVariablesExcludeEmptyConfigurationSource.cs
@@ -1,15 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.EnvironmentVariables;
namespace Ray.BiliBiliTool.Config
{
///
- /// 自定义的排除空值的环境变量配置源
+ /// 自定义的排除空值的环境变量配置源
/// (用于取待默认的)
///
public class EnvironmentVariablesExcludeEmptyConfigurationSource : IConfigurationSource
diff --git a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs
index da828c8e7..810562797 100644
--- a/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs
+++ b/src/Ray.BiliBiliTool.Config/Options/DailyTaskOptions.cs
@@ -18,17 +18,26 @@ public class DailyTaskOptions
///
public bool IsShareVideo { get; set; }
+ ///
+ /// 是否开启专栏投币模式
+ ///
+ public bool IsDonateCoinForArticle { get; set; }
+
///
/// 每日设定的投币数 [0,5]
///
public int NumberOfCoins { get; set; } = 5;
+ ///
+ /// 要保留的硬币数量 [0,int_max]
+ ///
+ public int NumberOfProtectedCoins { get; set; } = 0;
+
///
/// 达到六级后是否开始白嫖
///
public bool SaveCoinsWhenLv6 { get; set; } = false;
-
///
/// 投币时是否点赞[false,true]
///
@@ -50,6 +59,7 @@ public class DailyTaskOptions
public string AutoChargeUpId { get; set; }
private string _chargeComment;
+
///
/// 充电后留言
///
@@ -77,16 +87,26 @@ public string ChargeComment
///
public string DevicePlatform { get; set; } = "android";
+ ///
+ /// 自定义漫画阅读 comic_id
+ ///
+ public long CustomComicId { get; set; } = 27355;
+
+ ///
+ /// 自定义漫画阅读 ep_id
+ ///
+ public long CustomEpId { get; set; } = 381662;
public List SupportUpIdList
{
get
{
- var re = new List();
- if (string.IsNullOrWhiteSpace(SupportUpIds) | SupportUpIds == "-1") return re;
+ List re = new();
+ if (string.IsNullOrWhiteSpace(SupportUpIds) | SupportUpIds == "-1")
+ return re;
- var array = SupportUpIds.Split(',');
- foreach (var item in array)
+ string[] array = SupportUpIds.Split(',');
+ foreach (string item in array)
{
if (long.TryParse(item.Trim(), out long upId))
re.Add(upId);
diff --git a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
index 5bbd4e513..40741ed87 100644
--- a/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
+++ b/src/Ray.BiliBiliTool.Console/BiliBiliToolHostedService.cs
@@ -45,25 +45,25 @@ IHostApplicationLifetime applicationLifetime
public async Task StartAsync(CancellationToken cancellationToken)
{
- var isNotifySingle = _configuration.GetSection("Notification:IsSingleAccountSingleNotify").Get();
+ bool isNotifySingle = _configuration.GetSection("Notification:IsSingleAccountSingleNotify").Get();
try
{
_logger.LogInformation("BiliBiliToolPro 开始运行...{newLine}", Environment.NewLine);
- var pass = await PreCheckAsync(cancellationToken);
- if (!pass) return;
+ bool pass = await PreCheckAsync(cancellationToken);
+ if (!pass)
+ return;
await RandomSleepAsync(cancellationToken);
- var tasks = await ReadTargetTasksAsync(cancellationToken);
+ string[] tasks = await ReadTargetTasksAsync(cancellationToken);
_logger.LogInformation("【目标任务】{tasks}", string.Join(",", tasks));
if (tasks.Contains("Login"))
{
await DoTasksAsync(tasks, cancellationToken);
}
-
else
{
for (int i = 0; i < _cookieStrFactory.Count; i++)
@@ -78,7 +78,7 @@ public async Task StartAsync(CancellationToken cancellationToken)
{
LogAppInfo();
- var accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : "";
+ string accountName = _cookieStrFactory.Count > 1 ? $"账号【{_cookieStrFactory.CurrentNum}】" : "";
_logger.LogInformation("·开始推送·{task}·{user}", $"{_configuration["RunTasks"]}任务", accountName);
}
}
@@ -134,7 +134,8 @@ private Task PreCheckAsync(CancellationToken cancellationToken)
private async Task RandomSleepAsync(CancellationToken cancellationToken)
{
- if (_configuration["RunTasks"].Contains("Login") || _configuration["RunTasks"].Contains("Test")) return;
+ if (_configuration["RunTasks"].Contains("Login") || _configuration["RunTasks"].Contains("Test"))
+ return;
if (_securityOptions.RandomSleepMaxMin > 0)
{
@@ -144,9 +145,14 @@ private async Task RandomSleepAsync(CancellationToken cancellationToken)
}
}
+ ///
+ /// 读取目标任务
+ ///
+ ///
+ ///
private Task ReadTargetTasksAsync(CancellationToken cancellationToken)
{
- var tasks = _configuration["RunTasks"]
+ string[] tasks = _configuration["RunTasks"]
.Split("&", options: StringSplitOptions.RemoveEmptyEntries);
if (tasks.Any())
{
@@ -159,11 +165,11 @@ private Task ReadTargetTasksAsync(CancellationToken cancellationToken)
while (true)
{
- var index = System.Console.ReadLine();
- var suc = int.TryParse(index, out int num);
+ string index = System.Console.ReadLine();
+ bool suc = int.TryParse(index, out int num);
if (suc)
{
- var code = TaskTypeFactory.GetCodeByIndex(num);
+ string code = TaskTypeFactory.GetCodeByIndex(num);
_configuration["RunTasks"] = code;
return Task.FromResult(new string[] { code });
}
@@ -174,17 +180,17 @@ private Task ReadTargetTasksAsync(CancellationToken cancellationToken)
private async Task DoTasksAsync(string[] tasks, CancellationToken cancellationToken)
{
- using var scope = _serviceProvider.CreateScope();
- foreach (var task in tasks)
+ using IServiceScope scope = _serviceProvider.CreateScope();
+ foreach (string task in tasks)
{
- var type = TaskTypeFactory.Create(task);
+ Type type = TaskTypeFactory.Create(task);
if (type == null)
{
_logger.LogWarning("任务不存在:{task}", task);
continue;
}
- var appService = (IAppService)scope.ServiceProvider.GetRequiredService(type);
+ IAppService appService = (IAppService)scope.ServiceProvider.GetRequiredService(type);
await appService?.DoTaskAsync(cancellationToken);
}
}
diff --git a/src/Ray.BiliBiliTool.Console/Program.cs b/src/Ray.BiliBiliTool.Console/Program.cs
index 7dc7ce0a1..0e3da4a4a 100644
--- a/src/Ray.BiliBiliTool.Console/Program.cs
+++ b/src/Ray.BiliBiliTool.Console/Program.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
@@ -56,7 +54,8 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
//hostBuilder.UseContentRoot(Directory.GetCurrentDirectory());
- //承载系统自身的配置:
+ #region 承载系统自身的配置
+
hostBuilder.ConfigureHostConfiguration(hostConfigurationBuilder =>
{
hostConfigurationBuilder.AddEnvironmentVariables(prefix: "DOTNET_");
@@ -67,22 +66,26 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
}
});
- //应用配置:
+ #endregion 承载系统自身的配置
+
+ #region 应用配置
+
hostBuilder.ConfigureAppConfiguration((hostBuilderContext, configurationBuilder) =>
{
Global.HostingEnvironment = hostBuilderContext.HostingEnvironment;
IHostEnvironment env = hostBuilderContext.HostingEnvironment;
//json文件:
+ string envName = hostBuilderContext.HostingEnvironment.EnvironmentName;
configurationBuilder.AddJsonFile("appsettings.json", true, true)
- .AddJsonFile($"appsettings.{hostBuilderContext.HostingEnvironment.EnvironmentName}.json", true, true)
+ .AddJsonFile($"appsettings.{envName}.json", true, true)
;
//用户机密:
if (env.IsDevelopment() && env.ApplicationName?.Length > 0)
{
//var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
- var appAssembly = Assembly.GetAssembly(typeof(Program));
+ Assembly appAssembly = Assembly.GetAssembly(typeof(Program));
configurationBuilder.AddUserSecrets(appAssembly, optional: true, reloadOnChange: true);
}
@@ -104,16 +107,23 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
configurationBuilder.AddInMemoryCollection(Config.Constants.GetDonateCoinCanContinueStatusDic());
});
- //日志:
+ #endregion 应用配置
+
+ #region 日志
+
hostBuilder.ConfigureLogging((hostBuilderContext, loggingBuilder) =>
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostBuilderContext.Configuration)
.CreateLogger();
SelfLog.Enable(x => System.Console.WriteLine(x ?? ""));
- }).UseSerilog();
+ })
+ .UseSerilog();
+
+ #endregion 日志
+
+ #region DI容器
- //DI容器:
hostBuilder.ConfigureServices((hostContext, services) =>
{
Global.ConfigurationRoot = (IConfigurationRoot)hostContext.Configuration;
@@ -126,9 +136,14 @@ internal static IHostBuilder CreateHostBuilder(string[] args)
services.AddAppServices();
});
+ #endregion DI容器
+
return hostBuilder;
}
+ ///
+ /// 输出本工具启动logo
+ ///
private static void PrintLogo()
{
System.Console.WriteLine(@" ____ ____ _ _____ _ ");
diff --git a/src/Ray.BiliBiliTool.Console/appsettings.json b/src/Ray.BiliBiliTool.Console/appsettings.json
index 89740733a..d92fc1e05 100644
--- a/src/Ray.BiliBiliTool.Console/appsettings.json
+++ b/src/Ray.BiliBiliTool.Console/appsettings.json
@@ -6,7 +6,9 @@
"Cron": "0 15 * * *",
"IsWatchVideo": true, //是否观看视频
"IsShareVideo": true, //是否分享视频
+ "IsDonateCoinForArticle": false,
"NumberOfCoins": 5, //每日设定的投币数 [0,5]
+ "NumberOfProtectedCoins": 0, // 要保留的硬币数量 [0,int_max],0 为不保留,int_max 通常取 (2^31)-1
"SaveCoinsWhenLv6": false, //达到六级后是否开始白嫖[false,true]
"SelectLike": true, //投币时是否同时点赞[false,true]
"SupportUpIds": "", //优先选择支持的up主Id集合,多个以英文逗号分隔,如:"123,456"。配置后会优先从指定的up主下挑选视频进行观看、分享和投币,不配置或配置为-1则表示没有特别支持的up,会从关注和排行耪中随机获取支持视频
@@ -15,7 +17,9 @@
"ChargeComment": "", //充电后留言
"DayOfReceiveVipPrivilege": 1, //每月几号自动领取会员权益的[-1,31],-1表示不指定,默认每月1号;0表示不自动领取
"DayOfExchangeSilver2Coin": 0, //每月几号执行银瓜子兑换硬币[-1,31],-1表示不指定,默认每月最后一天;-2表示每天;0表示不进行兑换
- "DevicePlatform": "android" //执行客户端操作时的平台 [ios,android]
+ "DevicePlatform": "android", //执行客户端操作时的平台 [ios,android]
+ "CustomComicId": 27355, //自定义漫画阅读 comic_id,若不清楚含义请勿修改
+ "CustomEpId": 381662 //自定义漫画阅读 ep_id,若不清楚含义请勿修改
},
"LiveLotteryTaskConfig": {
diff --git a/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs b/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs
index efa7f6e68..e6d12dae5 100644
--- a/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs
+++ b/src/Ray.BiliBiliTool.DomainService/AccountDomainService.cs
@@ -25,6 +25,7 @@ public class AccountDomainService : IAccountDomainService
private readonly IRelationApi _relationApi;
private readonly UnfollowBatchedTaskOptions _unfollowBatchedTaskOptions;
private readonly BiliCookie _cookie;
+ private readonly DailyTaskOptions _dailyTaskOptions;
public AccountDomainService(
ILogger logger,
@@ -32,14 +33,15 @@ public AccountDomainService(
BiliCookie cookie,
IUserInfoApi userInfoApi,
IRelationApi relationApi,
- IOptionsMonitor unfollowBatchedTaskOptions
- )
+ IOptionsMonitor unfollowBatchedTaskOptions,
+ IOptionsMonitor dailyTaskOptions)
{
_logger = logger;
_dailyTaskApi = dailyTaskApi;
_cookie = cookie;
_userInfoApi = userInfoApi;
_relationApi = relationApi;
+ _dailyTaskOptions = dailyTaskOptions.CurrentValue;
_unfollowBatchedTaskOptions = unfollowBatchedTaskOptions.CurrentValue;
}
@@ -66,9 +68,9 @@ public async Task LoginByCookie()
if (useInfo.Level_info.Current_level < 6)
{
- _logger.LogInformation("【距升级Lv{0}】{1}天(如每日做满65点经验)",
+ _logger.LogInformation("【距升级Lv{0}】预计{1}天",
useInfo.Level_info.Current_level + 1,
- (useInfo.Level_info.GetNext_expLong() - useInfo.Level_info.Current_exp) / Constants.EveryDayExp);
+ CalculateUpgradeTime(useInfo));
}
else
{
@@ -216,5 +218,42 @@ private async Task GetTag(string groupName)
TagDto tag = tagList.FirstOrDefault(x => x.Name == groupName);
return tag;
}
+
+ ///
+ /// 计算升级时间
+ ///
+ ///
+ /// 升级时间
+ public int CalculateUpgradeTime(UserInfo useInfo)
+ {
+ double availableCoins = decimal.ToDouble(useInfo.Money ?? 0) - _dailyTaskOptions.NumberOfProtectedCoins;
+ long needExp = useInfo.Level_info.GetNext_expLong() - useInfo.Level_info.Current_exp;
+ int needDay;
+
+ if (availableCoins < 0)
+ needDay = (int)((double)needExp / 25 + _dailyTaskOptions.NumberOfProtectedCoins - Math.Abs(availableCoins));
+
+ switch (_dailyTaskOptions.NumberOfCoins)
+ {
+ case 0:
+ needDay = (int)(needExp / 15);
+ break;
+ case 1:
+ needDay = (int)(needExp / 25);
+ break;
+ default:
+ int dailyExpAvailable = 15 + _dailyTaskOptions.NumberOfCoins * 10;
+ double needFrontDay = availableCoins / (_dailyTaskOptions.NumberOfCoins - 1);
+
+ if ((double)needExp / dailyExpAvailable > needFrontDay)
+ needDay = (int)(needFrontDay + (needExp - dailyExpAvailable * needFrontDay) / 25);
+ else
+ needDay= (int)(needExp / dailyExpAvailable );
+ break;
+ }
+
+ return needDay;
+ }
+
}
}
diff --git a/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs b/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs
new file mode 100644
index 000000000..bda778dba
--- /dev/null
+++ b/src/Ray.BiliBiliTool.DomainService/ArticleDomainService.cs
@@ -0,0 +1,395 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Polly;
+using Ray.BiliBiliTool.Agent;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.Article;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces;
+using Ray.BiliBiliTool.Config.Options;
+using Ray.BiliBiliTool.DomainService.Interfaces;
+
+namespace Ray.BiliBiliTool.DomainService;
+
+public class ArticleDomainService : IArticleDomainService
+{
+ private readonly IArticleApi _articleApi;
+ private readonly BiliCookie _biliCookie;
+ private readonly ILogger _logger;
+ private readonly DailyTaskOptions _dailyTaskOptions;
+ private readonly ICoinDomainService _coinDomainService;
+ private readonly IAccountApi _accountApi;
+ private readonly IWbiDomainService _wbiDomainService;
+
+
+ ///
+ /// up的专栏总数缓存
+ ///
+ private readonly Dictionary _upArticleCountDicCatch = new();
+
+ ///
+ /// 已对投币数量缓存
+ ///
+ private readonly Dictionary _alreadyDonatedCoinCountCatch = new();
+
+ public ArticleDomainService(
+ IArticleApi articleApi,
+ BiliCookie biliCookie,
+ ILogger logger,
+ IOptionsMonitor dailyTaskOptions,
+ ICoinDomainService coinDomainService,
+ IAccountApi accountApi, IWbiDomainService wbiDomainService)
+ {
+ _articleApi = articleApi;
+ _biliCookie = biliCookie;
+ _logger = logger;
+ _coinDomainService = coinDomainService;
+ _accountApi = accountApi;
+ _wbiDomainService = wbiDomainService;
+ _dailyTaskOptions = dailyTaskOptions.CurrentValue;
+ }
+
+
+
+ public async Task LikeArticle(long cvid)
+ {
+ await _articleApi.Like(cvid, _biliCookie.BiliJct);
+ }
+
+ ///
+ /// 投币专栏任务
+ ///
+ ///
+ public async Task AddCoinForArticles()
+ {
+
+ var donateCoinsCounts = await CalculateDonateCoinsCounts();
+
+ if (donateCoinsCounts == 0)
+ {
+ // 没有可投的币相当于投币任务全部完成
+ return true;
+ }
+
+
+ int success = 0;
+ int tryCount = 10;
+
+ for (int i = 0; i <= tryCount && success < donateCoinsCounts; i++)
+ {
+ _logger.LogDebug("开始尝试第{num}次", i);
+
+ var upId = GetUpFromConfigUps();
+ var cvid = await GetRandomArticleFromUp(upId);
+ if (upId == 0 || cvid == 0)
+ {
+ _logger.LogInformation("未添加支持的Up主,任务跳过");
+ return false;
+ }
+
+ if (await AddCoinForArticle(cvid, upId))
+ {
+ // 点赞
+ if (_dailyTaskOptions.SelectLike)
+ {
+ await LikeArticle(cvid);
+ _logger.LogInformation("文章点赞成功");
+ }
+ success++;
+ }
+
+
+ }
+
+ if (success == donateCoinsCounts)
+ _logger.LogInformation("专栏投币任务完成");
+ else
+ {
+ _logger.LogInformation("投币尝试超过10次,已终止");
+ return false;
+ }
+
+
+ _logger.LogInformation("【硬币余额】{coin}", (await _accountApi.GetCoinBalance()).Data.Money ?? 0);
+
+ return true;
+ }
+
+
+ ///
+ /// 给某一篇专栏投币
+ ///
+ /// 文章cvid
+ /// 文章作者mid
+ /// 投币是否成功(false 投币失败,true 投币成功)
+ public async Task AddCoinForArticle(long cvid, long mid)
+ {
+ BiliApiResponse result;
+ try
+ {
+ var refer = $"https://www.bilibili.com/read/cv{cvid}/?from=search&spm_id_from=333.337.0.0";
+ result = await _articleApi.AddCoinForArticle(new AddCoinForArticleRequest(cvid, mid, _biliCookie.BiliJct),
+ refer);
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+
+ if (result.Code == 0)
+ {
+ _logger.LogInformation("投币成功,经验+10 √");
+ return true;
+ }
+ else
+ {
+ _logger.LogError("投币错误 {message}", result.Message);
+ return false;
+ }
+ }
+
+
+ #region private
+
+ ///
+ /// 从某个up主中随机挑选一个专栏
+ ///
+ ///
+ /// 专栏的cvid
+ private async Task GetRandomArticleFromUp(long mid)
+ {
+ if (!_upArticleCountDicCatch.TryGetValue(mid, out int articleCount))
+ {
+ articleCount = await GetArticleCountOfUp(mid);
+ _upArticleCountDicCatch.Add(mid, articleCount);
+ }
+
+ // 专栏数为0时
+ if (articleCount == 0)
+ {
+ return 0;
+ }
+
+ var req = new SearchArticlesByUpIdDto()
+ {
+ Mid = mid,
+ Ps = 1,
+ Pn = new Random().Next(1, articleCount + 1)
+ };
+ var w_ridDto = await _wbiDomainService.GetWridAsync(req);
+
+ var fullDto = new SearchArticlesByUpIdFullDto()
+ {
+ Mid = mid,
+ Ps = req.Ps,
+ Pn = req.Pn,
+ w_rid = w_ridDto.w_rid,
+ wts = w_ridDto.wts
+ };
+
+ BiliApiResponse re = await _articleApi.SearchUpArticlesByUpId(fullDto);
+
+ if (re.Code != 0)
+ {
+ throw new Exception(re.Message);
+ }
+
+ ArticleInfo articleInfo = re.Data.Articles.FirstOrDefault();
+
+ _logger.LogDebug("获取到的专栏{cvid}({title})", articleInfo.Id, articleInfo.Title);
+
+ // 检查是否可投
+ if (!await IsCanDonate(articleInfo.Id))
+ {
+ return 0;
+ }
+
+ return articleInfo.Id;
+ }
+
+
+ // TODO 转变为异步代码
+ ///
+ /// 从支持UP主列表中随机挑选一位
+ ///
+ /// 被挑选up主的mid
+ private long GetUpFromConfigUps()
+ {
+ if (_dailyTaskOptions.SupportUpIdList == null || _dailyTaskOptions.SupportUpIdList.Count == 0)
+ {
+ return 0;
+ }
+
+ try
+ {
+ long randomUpId =
+ _dailyTaskOptions.SupportUpIdList[new Random().Next(0, _dailyTaskOptions.SupportUpIdList.Count)];
+
+ if (randomUpId is 0 or long.MinValue) return 0;
+
+ if (randomUpId.ToString() == _biliCookie.UserId)
+ {
+ _logger.LogDebug("不能为自己投币");
+ return 0;
+ }
+ _logger.LogDebug("挑选出的up主为{UpId}",randomUpId);
+ return randomUpId;
+ }
+ catch (Exception e)
+ {
+ _logger.LogWarning("异常:{msg}", e);
+ }
+
+ return 0;
+ }
+
+ ///
+ /// 获取Up主专栏总数
+ ///
+ /// up主mid
+ /// 专栏总数
+ ///
+ private async Task GetArticleCountOfUp(long mid)
+ {
+ var req = new SearchArticlesByUpIdDto()
+ {
+ Mid = mid
+ };
+
+ var w_ridDto = await _wbiDomainService.GetWridAsync(req);
+
+ var fullDto = new SearchArticlesByUpIdFullDto()
+ {
+ Mid = mid,
+ w_rid = w_ridDto.w_rid,
+ wts = w_ridDto.wts
+ };
+
+ BiliApiResponse re = await _articleApi.SearchUpArticlesByUpId(fullDto);
+
+ if (re.Code != 0)
+ {
+ throw new Exception(re.Message);
+ }
+
+ return re.Data.Count;
+ }
+
+ ///
+ /// 计算所需要投的硬币数量
+ ///
+ /// 硬币数量
+ private async Task CalculateDonateCoinsCounts()
+ {
+ int needCoins = await GetNeedDonateCoinCounts();
+
+ int protectedCoins = _dailyTaskOptions.NumberOfProtectedCoins;
+ if (needCoins <= 0) return 0;
+
+ //投币前硬币余额
+ decimal coinBalance = await _coinDomainService.GetCoinBalance();
+ _logger.LogInformation("【投币前余额】 : {coinBalance}", coinBalance);
+ _ = int.TryParse(decimal.Truncate(coinBalance - protectedCoins).ToString(), out int unprotectedCoins);
+
+ if (coinBalance <= 0)
+ {
+ _logger.LogInformation("因硬币余额不足,今日暂不执行投币任务");
+ return 0;
+ }
+
+ if (coinBalance <= protectedCoins)
+ {
+ _logger.LogInformation("因硬币余额达到或低于保留值,今日暂不执行投币任务");
+ return 0;
+ }
+
+ //余额小于目标投币数,按余额投
+ if (coinBalance < needCoins)
+ {
+ _ = int.TryParse(decimal.Truncate(coinBalance).ToString(), out needCoins);
+ _logger.LogInformation("因硬币余额不足,目标投币数调整为: {needCoins}", needCoins);
+ return needCoins;
+ }
+
+ //投币后余额小于等于保护值,按保护值允许投
+ if (coinBalance - needCoins <= protectedCoins)
+ {
+ //排除需投等于保护后可投数量相等时的情况
+ if (unprotectedCoins != needCoins)
+ {
+ needCoins = unprotectedCoins;
+ _logger.LogInformation("因硬币余额投币后将达到或低于保留值,目标投币数调整为: {needCoins}", needCoins);
+ return needCoins;
+ }
+ }
+
+ return needCoins;
+ }
+
+ private async Task GetNeedDonateCoinCounts()
+ {
+ int configCoins = _dailyTaskOptions.NumberOfCoins;
+
+ if (configCoins <= 0)
+ {
+ _logger.LogInformation("已配置为跳过投币任务");
+ return configCoins;
+ }
+
+ //已投的硬币
+ int alreadyCoins = await _coinDomainService.GetDonatedCoins();
+
+ int targetCoins = configCoins;
+
+ _logger.LogInformation("【今日已投】{already}枚", alreadyCoins);
+ _logger.LogInformation("【目标欲投】{already}枚", targetCoins);
+
+ if (targetCoins > alreadyCoins)
+ {
+ int needCoins = targetCoins - alreadyCoins;
+ _logger.LogInformation("【还需再投】{need}枚", needCoins);
+ return needCoins;
+ }
+
+ _logger.LogInformation("已完成投币任务,不需要再投啦~");
+ return 0;
+ }
+
+
+ private async Task IsCanDonate(long cvid)
+ {
+ try
+ {
+ if (_alreadyDonatedCoinCountCatch.Any(x => x.Key == cvid.ToString()))
+ {
+ _logger.LogDebug("重复专栏,丢弃处理");
+ return false;
+ }
+
+ if (!_alreadyDonatedCoinCountCatch.TryGetValue(cvid.ToString(), out int multiply))
+ {
+ multiply = (await _articleApi.SearchArticleInfo(cvid)).Data.Coin;
+ _alreadyDonatedCoinCountCatch.TryAdd(cvid.ToString(), multiply);
+ }
+
+ // 在网页端我测试时只能投一枚硬币,暂时设置最多投一枚
+ if (multiply >= 1)
+ {
+ return false;
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ _logger.LogWarning("异常:{mag}", e);
+ return false;
+ }
+ }
+
+ #endregion
+}
diff --git a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs
index 387afb54c..c989c595f 100644
--- a/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs
+++ b/src/Ray.BiliBiliTool.DomainService/DonateCoinDomainService.cs
@@ -70,11 +70,13 @@ IVideoApi videoApi
public async Task AddCoinsForVideos()
{
int needCoins = await GetNeedDonateCoinNum();
+ int protectedCoins = _dailyTaskOptions.NumberOfProtectedCoins;
if (needCoins <= 0) return;
//投币前硬币余额
decimal coinBalance = await _coinDomainService.GetCoinBalance();
_logger.LogInformation("【投币前余额】 : {coinBalance}", coinBalance);
+ _ = int.TryParse(decimal.Truncate(coinBalance - protectedCoins).ToString(), out int unprotectedCoins);
if (coinBalance <= 0)
{
@@ -82,6 +84,12 @@ public async Task AddCoinsForVideos()
return;
}
+ if (coinBalance <= protectedCoins)
+ {
+ _logger.LogInformation("因硬币余额达到或低于保留值,今日暂不执行投币任务");
+ return;
+ }
+
//余额小于目标投币数,按余额投
if (coinBalance < needCoins)
{
@@ -89,6 +97,17 @@ public async Task AddCoinsForVideos()
_logger.LogInformation("因硬币余额不足,目标投币数调整为: {needCoins}", needCoins);
}
+ //投币后余额小于等于保护值,按保护值允许投
+ if (coinBalance - needCoins <= protectedCoins)
+ {
+ //排除需投等于保护后可投数量相等时的情况
+ if (unprotectedCoins != needCoins)
+ {
+ needCoins = unprotectedCoins;
+ _logger.LogInformation("因硬币余额投币后将达到或低于保留值,目标投币数调整为: {needCoins}", needCoins);
+ }
+ }
+
int success = 0;
int tryCount = 10;
for (int i = 1; i <= tryCount && success < needCoins; i++)
@@ -105,7 +124,7 @@ public async Task AddCoinsForVideos()
}
if (success == needCoins)
- _logger.LogInformation("投币任务完成");
+ _logger.LogInformation("视频投币任务完成");
else
_logger.LogInformation("投币尝试超过10次,已终止");
@@ -400,7 +419,7 @@ private async Task IsCanDonate(string aid)
//已经投满2个币的,不能再投
if (!await IsDonatedLessThenLimitCoinsForVideo(aid))
{
- _logger.LogDebug("超出单个视频投币数量限制,丢弃处理", aid);
+ _logger.LogDebug("超出单个视频投币数量限制,丢弃处理");
return false;
}
diff --git a/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs b/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs
index b599bd78c..83d03da69 100644
--- a/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs
+++ b/src/Ray.BiliBiliTool.DomainService/Interfaces/IAccountDomainService.cs
@@ -24,5 +24,12 @@ public interface IAccountDomainService : IDomainService
/// 批量取关
///
Task UnfollowBatched();
+
+ ///
+ /// 计算升级时间
+ ///
+ ///
+ /// 升级时间
+ int CalculateUpgradeTime(UserInfo useInfo);
}
}
diff --git a/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs b/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs
new file mode 100644
index 000000000..f5a2f6d77
--- /dev/null
+++ b/src/Ray.BiliBiliTool.DomainService/Interfaces/IArticleDomainService.cs
@@ -0,0 +1,12 @@
+using System.Threading.Tasks;
+
+namespace Ray.BiliBiliTool.DomainService.Interfaces;
+
+public interface IArticleDomainService : IDomainService
+{
+ Task AddCoinForArticle(long cvid, long mid);
+
+ Task AddCoinForArticles();
+
+ Task LikeArticle(long cvid);
+}
diff --git a/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs b/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs
index 71e9fe23f..6cf387596 100644
--- a/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs
+++ b/src/Ray.BiliBiliTool.DomainService/LiveDomainService.cs
@@ -614,6 +614,14 @@ private async Task> GetFansMedalInfoList()
continue;
}
+ // 用以排除有牌子无直播间的up主
+ if (spaceInfo.Data.Live_room is null)
+ {
+ _logger.LogInformation("【主播】{name} 直播间id获取失败,已跳过",medal.Target_name);
+ continue;
+ }
+
+
var roomId = spaceInfo.Data.Live_room.Roomid;
// 获取直播间详细信息
diff --git a/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs b/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs
index 4459f4625..7d175a108 100644
--- a/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs
+++ b/src/Ray.BiliBiliTool.DomainService/MangaDomainService.cs
@@ -62,11 +62,12 @@ public async Task MangaSign()
///
public async Task MangaRead()
{
- BiliApiResponse response = await _mangaApi.ReadManga(_dailyTaskOptions.DevicePlatform);
+ if ( _dailyTaskOptions.CustomComicId <= 0 ) return;
+ BiliApiResponse response = await _mangaApi.ReadManga(_dailyTaskOptions.DevicePlatform, _dailyTaskOptions.CustomComicId, _dailyTaskOptions.CustomEpId);
if (response.Code == 0)
{
- _logger.LogInformation("【漫画阅读】成功, 阅读漫画为:堀与宫村");
+ _logger.LogInformation("【漫画阅读】成功");
}
else
{
diff --git a/test/AppServiceTest/VipServiceTest.cs b/test/AppServiceTest/VipServiceTest.cs
new file mode 100644
index 000000000..f50bafe0d
--- /dev/null
+++ b/test/AppServiceTest/VipServiceTest.cs
@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Ray.BiliBiliTool.Application.Contracts;
+using Ray.BiliBiliTool.Infrastructure;
+
+namespace AppServiceTest;
+
+public class VipServiceTest
+{
+ public VipServiceTest()
+ {
+ Program.CreateHost(new[] { "--ENVIRONMENT=Development" });
+ }
+
+ [Fact]
+ public async Task VipExpressTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+ var appService = scope.ServiceProvider.GetRequiredService();
+ await appService.VipExpress();
+ }
+}
diff --git a/test/BiliAgentTest/VipApiTest.cs b/test/BiliAgentTest/VipApiTest.cs
new file mode 100644
index 000000000..3e540a0a2
--- /dev/null
+++ b/test/BiliAgentTest/VipApiTest.cs
@@ -0,0 +1,59 @@
+using System.Threading.Tasks;
+using Xunit;
+using Microsoft.Extensions.DependencyInjection;
+using Ray.BiliBiliTool.Agent;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos.VipTask;
+using Ray.BiliBiliTool.Console;
+using Ray.BiliBiliTool.Infrastructure;
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Interfaces;
+using Xunit.Abstractions;
+namespace BiliAgentTest;
+
+public class VipApiTest
+{
+ private readonly ITestOutputHelper _output;
+ public VipApiTest(ITestOutputHelper output)
+ {
+ _output = output;
+ Program.CreateHost(new[] { "--ENVIRONMENT=Development" });
+ }
+
+ [Fact]
+ public async Task VipInfoTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+
+ var ck = scope.ServiceProvider.GetRequiredService();
+ var api = scope.ServiceProvider.GetRequiredService();
+
+ var re = await api.GetVouchersInfo();
+ if (re.Code == 0)
+ {
+ var info = re.Data.List.Find(x => x.Type == 9);
+ if (info != null)
+ {
+ _output.WriteLine(info.State.ToString());
+ }
+ else
+ {
+ _output.WriteLine("error");
+ }
+ }
+ }
+
+
+ [Fact]
+ public async Task GetVipExperienceTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+
+ var ck = scope.ServiceProvider.GetRequiredService();
+ var api = scope.ServiceProvider.GetRequiredService();
+ var re = await api.GetVipExperience(new VipExperienceRequest()
+ {
+ csrf = ck.BiliJct
+ });
+
+ _output.WriteLine(re.Message);
+ }
+}
diff --git a/test/DomainServiceTest/ArticleDomainServiceTest.cs b/test/DomainServiceTest/ArticleDomainServiceTest.cs
new file mode 100644
index 000000000..6f9d268e4
--- /dev/null
+++ b/test/DomainServiceTest/ArticleDomainServiceTest.cs
@@ -0,0 +1,47 @@
+using Xunit.Abstractions;
+
+namespace DomainServiceTest;
+
+public class ArticleDomainServiceTest
+{
+ private readonly ITestOutputHelper _output;
+ public ArticleDomainServiceTest(ITestOutputHelper output)
+ {
+ _output = output;
+ Program.CreateHost(new[] { "--ENVIRONMENT=Development" });
+ }
+
+ [Fact]
+ public async Task LikeArticleTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+ var config = Global.ConfigurationRoot;
+ var domainService = scope.ServiceProvider.GetRequiredService();
+ await domainService.LikeArticle(5806746);
+ }
+
+
+ [Fact]
+ public async Task AddCoinForArticleTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+ var config = Global.ConfigurationRoot;
+ var domainService = scope.ServiceProvider.GetRequiredService();
+
+ // 测试用的专栏:https://www.bilibili.com/read/cv5806746/?from=search&spm_id_from=333.337.0.0
+
+ await domainService.AddCoinForArticle(5806746, 486980924);
+ }
+
+
+ [Fact]
+ public async Task AddCoinForArticlesTest()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+ var config = Global.ConfigurationRoot;
+ var domainService = scope.ServiceProvider.GetRequiredService();
+ await domainService.AddCoinForArticles();
+ }
+
+
+}
diff --git a/test/DomainServiceTest/CalculateUpgradeTimeTest.cs b/test/DomainServiceTest/CalculateUpgradeTimeTest.cs
new file mode 100644
index 000000000..b9b70df03
--- /dev/null
+++ b/test/DomainServiceTest/CalculateUpgradeTimeTest.cs
@@ -0,0 +1,48 @@
+using Ray.BiliBiliTool.Agent.BiliBiliAgent.Dtos;
+
+namespace DomainServiceTest;
+
+public class CalculateUpgradeTimeTest
+{
+ public CalculateUpgradeTimeTest()
+ {
+ Program.CreateHost(new[] { "--ENVIRONMENT=Development" });
+ }
+
+ [Fact]
+ public void TestCalculateUpgradeTime()
+ {
+ using var scope = Global.ServiceProviderRoot.CreateScope();
+ var accountDomainService = scope.ServiceProvider.GetRequiredService();
+ int needDay = accountDomainService.CalculateUpgradeTime(new UserInfo()
+ {
+ Money = 7,
+ Level_info = new LevelInfo()
+ {
+ Current_level = 5,
+ Current_exp = 100,
+ Next_exp = 200
+ }
+ });
+ int needDay2 = accountDomainService.CalculateUpgradeTime(new UserInfo()
+ {
+ Money = 7,
+ Level_info = new LevelInfo()
+ {
+ Current_level = 5,
+ Current_exp = 1000,
+ Next_exp = 2000
+ }
+ });
+
+ Assert.Equal(1,needDay);
+ Assert.Equal(37,needDay2);
+
+ }
+}
+
+
+
+
+
+