feat: init
This commit is contained in:
72
modules/proxy/logic.go
Normal file
72
modules/proxy/logic.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
|
||||
"dyproxy/.gen/model"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func (p *Proxy) processFollowers(body []byte) {
|
||||
var follower Follower
|
||||
if err := json.Unmarshal(body, &follower); err != nil {
|
||||
err = errors.Wrap(err, "unmarshal followers")
|
||||
logrus.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
followers := []model.Follower{}
|
||||
for _, f := range follower.Followers {
|
||||
m := model.Follower{
|
||||
Avatar: f.AvatarThumb.URLList[0],
|
||||
Nickname: f.Nickname,
|
||||
SecUID: f.SecUID,
|
||||
ShortID: f.ShortID,
|
||||
UID: f.UID,
|
||||
UniqueID: f.UniqueID,
|
||||
ExpertUID: follower.MyselfUserID,
|
||||
}
|
||||
|
||||
logrus.Warnf("follower: %+v", m)
|
||||
followers = append([]model.Follower{m}, followers...)
|
||||
}
|
||||
|
||||
// post followers
|
||||
if _, err := p.client.R().SetBody(followers).Post("/api/followers"); err != nil {
|
||||
logrus.Error("post /api/followers, ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Proxy) processUserInfo(body []byte) {
|
||||
pattern := `self.__pace_f.push\(.*?"uid\\":\\"(.*?)\\",.*?\\"secUid\\":\\"(.*?)\\",.*?\\"shortId\\":\\"(.*?)\\",.*\\"realName\\":\\"(.*?)\\",.*?"nickname\\":\\"(.*?)\\",.*?`
|
||||
reg := regexp.MustCompile(pattern)
|
||||
|
||||
matches := reg.FindSubmatch(body)
|
||||
if len(matches) == 0 {
|
||||
logrus.Error("no match users")
|
||||
return
|
||||
}
|
||||
|
||||
if len(matches) != 6 {
|
||||
logrus.Error("invalid match")
|
||||
return
|
||||
}
|
||||
|
||||
expert := model.Expert{
|
||||
UID: string(matches[1]),
|
||||
SecUID: string(matches[2]),
|
||||
ShortID: string(matches[3]),
|
||||
RealName: string(matches[4]),
|
||||
NickName: string(matches[5]),
|
||||
}
|
||||
|
||||
logrus.Warnf("expert: %+v", expert)
|
||||
|
||||
// post user info
|
||||
if _, err := p.client.R().SetBody(expert).Post("/api/experts"); err != nil {
|
||||
logrus.Error("post /api/experts, ", err)
|
||||
}
|
||||
}
|
||||
70
modules/proxy/opt_follower.go
Normal file
70
modules/proxy/opt_follower.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/elazarl/goproxy.v1"
|
||||
)
|
||||
|
||||
type Follower struct {
|
||||
Extra struct {
|
||||
FatalItemIds []any `json:"fatal_item_ids"`
|
||||
Logid string `json:"logid"`
|
||||
Now int64 `json:"now"`
|
||||
} `json:"extra"`
|
||||
Followers []struct {
|
||||
AvatarThumb struct {
|
||||
Height int `json:"height"`
|
||||
URI string `json:"uri"`
|
||||
URLList []string `json:"url_list"`
|
||||
Width int `json:"width"`
|
||||
} `json:"avatar_thumb"`
|
||||
Nickname string `json:"nickname"`
|
||||
SecUID string `json:"sec_uid"`
|
||||
ShortID string `json:"short_id"`
|
||||
UID string `json:"uid"`
|
||||
UniqueID string `json:"unique_id"`
|
||||
UniqueIDModifyTime int `json:"unique_id_modify_time"`
|
||||
} `json:"followers"`
|
||||
HasMore bool `json:"has_more"`
|
||||
MyselfUserID string `json:"myself_user_id"`
|
||||
Offset int `json:"offset"`
|
||||
RecHasMore bool `json:"rec_has_more"`
|
||||
StatusCode int `json:"status_code"`
|
||||
StorePage string `json:"store_page"`
|
||||
Total int `json:"total"`
|
||||
VcdCount int `json:"vcd_count"`
|
||||
}
|
||||
|
||||
func WithFollower() Option {
|
||||
return func(p *Proxy) {
|
||||
p.proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||
if resp.StatusCode != 200 {
|
||||
return resp
|
||||
}
|
||||
|
||||
if resp.Request.Host != "www.douyin.com" {
|
||||
return resp
|
||||
}
|
||||
|
||||
if resp.Request.URL.Path != "/aweme/v1/web/user/follower/list/" {
|
||||
return resp
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return resp
|
||||
}
|
||||
resp.Body.Close()
|
||||
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||
|
||||
go p.processFollowers(body)
|
||||
|
||||
return resp
|
||||
})
|
||||
}
|
||||
}
|
||||
75
modules/proxy/opt_user_info.go
Normal file
75
modules/proxy/opt_user_info.go
Normal file
@@ -0,0 +1,75 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"gopkg.in/elazarl/goproxy.v1"
|
||||
)
|
||||
|
||||
type UserInfo struct {
|
||||
UID string
|
||||
SecUID string
|
||||
ShortID string
|
||||
RealName string
|
||||
Nickname string
|
||||
}
|
||||
|
||||
func WithUserInfo(duration int) Option {
|
||||
return func(p *Proxy) {
|
||||
p.proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||
if resp.StatusCode != 200 {
|
||||
return resp
|
||||
}
|
||||
|
||||
if resp.Request.Host != "www.douyin.com" {
|
||||
return resp
|
||||
}
|
||||
|
||||
if resp.Request.URL.Path != "/user/self" {
|
||||
return resp
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
return resp
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
// 添加定时刷新
|
||||
codes := `
|
||||
<!------------------->
|
||||
<script nonce>
|
||||
var hookFans = function (){
|
||||
document.querySelector('div[data-e2e="user-info-fans"]').click()
|
||||
setTimeout( () => document.querySelector('div[data-e2e="user-fans-container"]').parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.querySelector('svg').parentElement.click(), 2*1000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<script nonce>
|
||||
if (location.href.startsWith("https://www.douyin.com/user/self")) {
|
||||
console.log(">>>>>>>>>>>>>>>>>>>>>>>>>> start hook fans")
|
||||
var interval = setInterval(hookFans, (%d+Math.random()*100 %% %d)*1000)
|
||||
// setTimeout(() => location.reload, 5*60*1000)
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<!------------------->
|
||||
`
|
||||
codes = fmt.Sprintf(codes, duration, duration)
|
||||
body = bytes.Replace(body, []byte("</head>"), []byte(codes), 1)
|
||||
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||
|
||||
// remove Content-Security-Policy
|
||||
resp.Header.Del("Content-Security-Policy")
|
||||
|
||||
go p.processUserInfo(body)
|
||||
|
||||
return resp
|
||||
})
|
||||
}
|
||||
}
|
||||
133
modules/proxy/serve.go
Normal file
133
modules/proxy/serve.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
_ "embed"
|
||||
|
||||
"github.com/imroc/req/v3"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"gopkg.in/elazarl/goproxy.v1"
|
||||
)
|
||||
|
||||
func ServeE(cmd *cobra.Command, args []string) error {
|
||||
duration, err := cmd.Flags().GetInt("duration")
|
||||
if err != nil {
|
||||
duration = 10
|
||||
}
|
||||
|
||||
host, err := cmd.Flags().GetString("host")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
host = strings.TrimSpace(host)
|
||||
if host == "" {
|
||||
logrus.Fatal("host is empty")
|
||||
}
|
||||
|
||||
logrus.SetLevel(logrus.WarnLevel)
|
||||
|
||||
debug, err := cmd.Flags().GetBool("debug")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return NewProxy(host, debug, duration).Serve(29999)
|
||||
}
|
||||
|
||||
func NewProxy(host string, debug bool, duration int) *Proxy {
|
||||
return New(
|
||||
WithHost(host),
|
||||
WithLogger(log.New(io.Discard, "", log.LstdFlags)),
|
||||
WithHttps(),
|
||||
WithDebug(debug),
|
||||
WithVerbose(),
|
||||
WithFollower(),
|
||||
WithUserInfo(duration),
|
||||
)
|
||||
}
|
||||
|
||||
type Option func(*Proxy)
|
||||
|
||||
func WithLogger(logger *log.Logger) Option {
|
||||
return func(p *Proxy) {
|
||||
p.proxy.Logger = logger
|
||||
// p.proxy.Logger = log.New(io.Discard, "", log.LstdFlags)
|
||||
}
|
||||
}
|
||||
|
||||
func WithVerbose() Option {
|
||||
return func(p *Proxy) {
|
||||
p.proxy.Verbose = true
|
||||
}
|
||||
}
|
||||
|
||||
func WithHttps() Option {
|
||||
return func(p *Proxy) {
|
||||
p.proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm)
|
||||
}
|
||||
}
|
||||
|
||||
func WithDebug(debug bool) Option {
|
||||
return func(p *Proxy) {
|
||||
if debug {
|
||||
p.client = p.client.DevMode()
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func WithHost(h string) Option {
|
||||
return func(p *Proxy) {
|
||||
logrus.Infof("post data to host: %s", h)
|
||||
p.client = req.C().
|
||||
SetBaseURL(h).
|
||||
EnableInsecureSkipVerify().
|
||||
SetTimeout(10*time.Second).
|
||||
SetCommonBasicAuth("rogeecn", "xixi@0202")
|
||||
}
|
||||
}
|
||||
|
||||
type Proxy struct {
|
||||
proxy *goproxy.ProxyHttpServer
|
||||
client *req.Client
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func New(opts ...Option) *Proxy {
|
||||
proxy := &Proxy{
|
||||
proxy: goproxy.NewProxyHttpServer(),
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(proxy)
|
||||
}
|
||||
|
||||
return proxy
|
||||
}
|
||||
|
||||
// run
|
||||
func (p *Proxy) Serve(port uint) error {
|
||||
logrus.Infof("douyin proxy start serve at: :%d", port)
|
||||
p.server = &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", port),
|
||||
Handler: p.proxy,
|
||||
}
|
||||
|
||||
return p.server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (p *Proxy) Shutdown() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
|
||||
defer cancel()
|
||||
|
||||
return p.server.Shutdown(ctx)
|
||||
}
|
||||
Reference in New Issue
Block a user