feat: 上线链接处理功能
This commit is contained in:
parent
c0cfacbd33
commit
22434ae5dd
120
handler/urlparser/url.go
Normal file
120
handler/urlparser/url.go
Normal file
@ -0,0 +1,120 @@
|
||||
package urlparser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"git.lxtend.com/qqbot/handler"
|
||||
"git.lxtend.com/qqbot/model"
|
||||
)
|
||||
|
||||
func init() {
|
||||
handler.RegisterFrontMatchHandler("[CQ:json,data=", urlParser)
|
||||
}
|
||||
|
||||
func urlParser(msg model.Message) (reply model.Reply) {
|
||||
qqdocurl, err := extractQQDocURL(msg.RawMsg)
|
||||
if err != nil {
|
||||
return model.Reply{
|
||||
ReplyMsg: fmt.Sprintf("解析失败: %v", err),
|
||||
ReferOriginMsg: true,
|
||||
FromMsg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
return model.Reply{
|
||||
ReplyMsg: qqdocurl,
|
||||
ReferOriginMsg: true,
|
||||
FromMsg: msg,
|
||||
}
|
||||
}
|
||||
|
||||
func extractQQDocURL(input string) (string, error) {
|
||||
// 使用正则表达式提取 JSON 数据部分
|
||||
re := regexp.MustCompile(`\{.*\}`)
|
||||
jsonPart := re.FindString(input)
|
||||
if jsonPart == "" {
|
||||
return "", fmt.Errorf("无法找到 JSON 数据部分")
|
||||
}
|
||||
|
||||
// 解析 JSON 数据
|
||||
var jsonData map[string]interface{}
|
||||
// 替换 HTML 实体为普通字符
|
||||
jsonPart = strings.ReplaceAll(jsonPart, ",", ",")
|
||||
jsonPart = strings.ReplaceAll(jsonPart, "[", "[")
|
||||
jsonPart = strings.ReplaceAll(jsonPart, "]", "]")
|
||||
jsonPart = strings.ReplaceAll(jsonPart, "&", "&")
|
||||
|
||||
if err := json.Unmarshal([]byte(jsonPart), &jsonData); err != nil {
|
||||
return "", fmt.Errorf("解析 JSON 失败: %w", err)
|
||||
}
|
||||
|
||||
// 定位到 meta -> detail_1 -> qqdocurl
|
||||
meta, ok := jsonData["meta"].(map[string]interface{})
|
||||
if !ok {
|
||||
return "", fmt.Errorf("找不到 meta 字段")
|
||||
}
|
||||
detail, ok := meta["detail_1"].(map[string]interface{})
|
||||
if !ok {
|
||||
return "", fmt.Errorf("找不到 detail_1 字段")
|
||||
}
|
||||
qqdocurl, ok := detail["qqdocurl"].(string)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("找不到 qqdocurl 字段")
|
||||
}
|
||||
|
||||
qqdocurl, _ = removeTrackingParams(qqdocurl)
|
||||
qqdocurl, _ = resolveFinalURL(qqdocurl)
|
||||
qqdocurl, _ = removeTrackingParams(qqdocurl)
|
||||
|
||||
return qqdocurl, nil
|
||||
}
|
||||
|
||||
func removeTrackingParams(rawURL string) (string, error) {
|
||||
parsedURL, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 仅保留 URL 的 Scheme 和 Host + Path 部分
|
||||
return fmt.Sprintf("%s://%s%s", parsedURL.Scheme, parsedURL.Host, parsedURL.Path), nil
|
||||
}
|
||||
|
||||
func resolveFinalURL(initialURL string) (string, error) {
|
||||
// 解析 URL 确保其格式正确
|
||||
parsedURL, err := url.Parse(initialURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("URL 解析失败: %w", err)
|
||||
}
|
||||
|
||||
// 创建一个 HTTP 客户端
|
||||
client := &http.Client{
|
||||
// 禁用自动重定向,以便手动处理 302
|
||||
CheckRedirect: func(req *http.Request, via []*http.Request) error {
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
|
||||
// 发起 GET 请求
|
||||
resp, err := client.Get(parsedURL.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("请求失败: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// 如果是 302 重定向,则递归访问新链接
|
||||
if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
|
||||
redirectURL, err := resp.Location()
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("解析重定向地址失败: %w", err)
|
||||
}
|
||||
fmt.Printf("重定向至: %s\n", redirectURL.String())
|
||||
return resolveFinalURL(redirectURL.String())
|
||||
}
|
||||
|
||||
// 返回最终的非 302 链接
|
||||
return initialURL, nil
|
||||
}
|
@ -6,5 +6,6 @@ import (
|
||||
_ "git.lxtend.com/qqbot/handler/headmaster"
|
||||
_ "git.lxtend.com/qqbot/handler/jrrp"
|
||||
_ "git.lxtend.com/qqbot/handler/scoresaber"
|
||||
_ "git.lxtend.com/qqbot/handler/urlparser"
|
||||
_ "git.lxtend.com/qqbot/handler/xibao"
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user