first commit

This commit is contained in:
mei 2025-08-28 17:41:46 +08:00
commit 91c3337f46
8 changed files with 200 additions and 0 deletions

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# 中V监测器
监测中V歌曲并通知到钉钉写的比较粗糙十分钟干完(距离凉雨传说还有几百播放的时候,最后成功检测到凉雨传说),搭配 NineVocalRank 使用
```shell
(base) mei@mei-SuperPC:~/work/v-alerm$ ./v-alarm
2025/08/28 14:58:34 &{{1000010 23104 35676 46579 9343 5842 3753} {396194 COPY 【洛天依原创】凉雨【PV付/COSMOSⅡ】 http://i1.hdslb.com/bfs/archive/dce146224f830f84618e1e3caffa42800ae611de.jpg 1 1756364314} {8786522 BV12x411y7SN 30} {6730 330 287 244 394 128 78} {9939.34 传说曲 7 10.0001}}
2025/08/28 14:58:39 &{{1000010 23104 35676 46579 9345 5842 3753} {396194 COPY 【洛天依原创】凉雨【PV付/COSMOSⅡ】 http://i1.hdslb.com/bfs/archive/dce146224f830f84618e1e3caffa42800ae611de.jpg 1 1756364319} {8786522 BV12x411y7SN 30} {6730 330 287 244 396 128 78} {9944.74 传说曲 7 10.0001}}
2025/08/28 14:58:44 &{{1000010 23104 35676 46579 9343 5842 3753} {396194 COPY 【洛天依原创】凉雨【PV付/COSMOSⅡ】 http://i1.hdslb.com/bfs/archive/dce146224f830f84618e1e3caffa42800ae611de.jpg 1 1756364324} {8786522 BV12x411y7SN 30} {6730 330 287 244 394 128 78} {9939.34 传说曲 7 10.0001}}
2025/08/28 14:58:49 &{{1000010 23104 35676 46579 9344 5842 3753} {396194 COPY 【洛天依原创】凉雨【PV付/COSMOSⅡ】 http://i1.hdslb.com/bfs/archive/dce146224f830f84618e1e3caffa42800ae611de.jpg 1 1756364329} {8786522 BV12x411y7SN 30} {6730 330 287 244 395 128 78} {9942.04 传说曲 7 10.0001}}
```

6
configs/config.go Normal file
View File

@ -0,0 +1,6 @@
package configs
const (
DingTalkURL = ""
BVID = "BV12x411y7SN"
)

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.mmeiblog.cn/mei/v-alarm
go 1.23.4
require github.com/robfig/cron v1.2.0

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ=
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=

24
internal/alerm.go Normal file
View File

@ -0,0 +1,24 @@
package internal
import (
"fmt"
"log"
"time"
"git.mmeiblog.cn/mei/v-alarm/configs"
)
func Alerm() {
SongData, err := Monitor(configs.BVID)
if err != nil {
log.Fatalln(err)
}
if SongData.Video_stat.View >= 1000000 {
timestamp := time.Unix(SongData.Video_info.Timestamp, 0)
message := fmt.Sprintf("歌曲%s已达成传说,信息输出在日志,达成时间:%s",
SongData.Video_info.Title,
timestamp.Format("2006-01-02 15:04:05"))
SendDingTalkNotification(message)
log.Println(SongData)
}
}

36
internal/dingTalk.go Normal file
View File

@ -0,0 +1,36 @@
package internal
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"git.mmeiblog.cn/mei/v-alarm/configs"
)
func SendDingTalkNotification(message string) error {
msg := map[string]any{
"msgtype": "text",
"text": map[string]string{"content": message},
}
jsonBytes, err := json.Marshal(msg)
if err != nil {
return err
}
req, err := http.NewRequest("POST", configs.DingTalkURL, strings.NewReader(string(jsonBytes)))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("钉钉API请求失败状态码: %d", resp.StatusCode)
}
return nil
}

90
internal/monitor.go Normal file
View File

@ -0,0 +1,90 @@
package internal
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
type SongMessage struct {
Video_stat VideoStat `json:"video_stat"`
Video_info VideoInfo `json:"video_info"`
Video_id VideoID `json:"video_id"`
Video_increase VideoIncrease `json:"video_increase"`
Vrank_info VrankInfo `json:"vrank_info"`
}
type VideoStat struct {
View int `json:"view"`
Like int `json:"like"`
Coin int `json:"coin"`
Favorite int `json:"favorite"`
Reply int `json:"reply"`
Share int `json:"share"`
Danmaku int `json:"danmaku"`
}
type VideoInfo struct {
Uploader_mid string `json:"uploader_mid"`
Uploader_name string `json:"uploader_name"`
Title string `json:"title"`
Pic string `json:"pic"`
Pages int `json:"pages"`
Timestamp int64 `json:"timestamp"`
}
type VideoID struct {
Avid string `json:"avid"`
Bvid string `json:"bvid"`
Tid int `json:"tid"`
}
type VideoIncrease struct {
View int `json:"view"`
Like int `json:"like"`
Coin int `json:"coin"`
Favorite int `json:"favorite"`
Reply int `json:"reply"`
Share int `json:"share"`
Danmaku int `json:"danmaku"`
}
type VrankInfo struct {
Vrank_score float64 `json:"vrank_score"`
Rank string `json:"rank"`
Rank_code int `json:"rank_code"`
Progress_percentage float64 `json:"progress_percentage"`
}
func Monitor(bvid string) (SongData *SongMessage, error error) {
url := fmt.Sprintf("https://api.mmeiblog.cn/NineVocalRank/vocaloid_rank/v1/video/%s", bvid)
method := "GET"
client := &http.Client{}
req, err := http.NewRequest(method, url, nil)
if err != nil {
log.Fatalln(err)
return
}
res, err := client.Do(req)
if err != nil {
log.Fatalln(err)
return
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
log.Fatalln(err)
return
}
var Data SongMessage
err = json.Unmarshal(body, &Data)
if err != nil {
log.Printf("解析JSON失败: %v\n", err)
return nil, err
}
return &Data, nil
}

26
main.go Normal file
View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"git.mmeiblog.cn/mei/v-alarm/internal"
"github.com/robfig/cron"
)
// 写的比较粗糙,十分钟干完(距离凉雨传说还有几百播放的时候,最后成功检测到凉雨传说)
func main() {
c := cron.New()
c.AddFunc("@every 5s", internal.Alerm)
c.Start()
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
<-sig // 阻塞直到收到信号
fmt.Printf("Hava a good Day!")
c.Stop() // 关闭 cron
}