Browse Source

新增 socks5 代理支持 #170

Signed-off-by: 716 <[email protected]>
716 3 years ago
parent
commit
55c2623570

+ 4 - 1
internal/logic/sub_supplier/shooter/shooter.go

@@ -158,7 +158,10 @@ func (s *Supplier) getSubInfos(fileHash, fileName, qLan string) ([]SublistShoote
 
 	var jsonList []SublistShooter
 
-	httpClient := my_util.NewHttpClient(s.settings.AdvancedSettings.ProxySettings)
+	httpClient, err := my_util.NewHttpClient(s.settings.AdvancedSettings.ProxySettings)
+	if err != nil {
+		return nil, err
+	}
 	resp, err := httpClient.R().
 		SetFormData(map[string]string{
 			"filehash": fileHash,

+ 4 - 1
internal/logic/sub_supplier/xunlei/xunlei.go

@@ -184,7 +184,10 @@ func (s *Supplier) getSubListFromFile(filePath string) ([]supplier.SubInfo, erro
 func (s *Supplier) getSubInfos(filePath, cid string) (SublistSliceXunLei, error) {
 	var jsonList SublistSliceXunLei
 
-	httpClient := my_util.NewHttpClient(s.settings.AdvancedSettings.ProxySettings)
+	httpClient, err := my_util.NewHttpClient(s.settings.AdvancedSettings.ProxySettings)
+	if err != nil {
+		return jsonList, err
+	}
 	resp, err := httpClient.R().
 		SetResult(&jsonList).
 		Get(fmt.Sprintf(s.settings.AdvancedSettings.SuppliersSettings.Xunlei.RootUrl, cid))

+ 68 - 37
internal/pkg/my_util/util.go

@@ -17,8 +17,11 @@ import (
 	"github.com/go-resty/resty/v2"
 	"github.com/google/uuid"
 	"github.com/sirupsen/logrus"
+	"golang.org/x/net/context"
+	"golang.org/x/net/proxy"
 	"io"
 	"math"
+	"net"
 	"net/http"
 	"net/url"
 	"os"
@@ -33,63 +36,85 @@ import (
 )
 
 // NewHttpClient 新建一个 resty 的对象
-func NewHttpClient(_proxySettings ...*settings.ProxySettings) *resty.Client {
+func NewHttpClient(_proxySettings ...*settings.ProxySettings) (*resty.Client, error) {
 	//const defUserAgent = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50"
 	//const defUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36 Edg/91.0.864.41"
 
 	var proxySettings *settings.ProxySettings
-	var HttpProxy, UserAgent, Referer string
+	var HttpProxyAddress, socket5ProxyAddress, UserAgent, Referer string
 
 	if len(_proxySettings) > 0 {
 		proxySettings = _proxySettings[0]
 		if proxySettings.UseHttpProxy == true && len(proxySettings.HttpProxyAddress) > 0 {
-			HttpProxy = proxySettings.HttpProxyAddress
+			HttpProxyAddress = proxySettings.HttpProxyAddress
+		}
+		if proxySettings.UseSocks5Proxy == true && len(proxySettings.Socks5ProxyAddress) > 0 {
+			socket5ProxyAddress = proxySettings.Socks5ProxyAddress
 		}
 	}
-
+	// ------------------------------------------------
 	// 随机的 Browser
 	UserAgent = browser.Random()
-
+	// ------------------------------------------------
 	httpClient := resty.New()
 	httpClient.SetTimeout(common.HTMLTimeOut)
 	httpClient.SetRetryCount(2)
-	if HttpProxy != "" {
-		httpClient.SetProxy(HttpProxy)
-
+	// ------------------------------------------------
+	// 设置 Referer
+	if len(_proxySettings) > 0 {
 		if len(proxySettings.Referer) > 0 {
 			Referer = proxySettings.Referer
 		}
-
 		if len(Referer) > 0 {
 			httpClient.SetHeader("Referer", Referer)
 		}
-	} else {
-		httpClient.RemoveProxy()
 	}
-
+	// ------------------------------------------------
+	// 设置 Header
 	httpClient.SetHeaders(map[string]string{
 		"Content-Type": "application/json",
 		"User-Agent":   UserAgent,
 	})
-
+	// ------------------------------------------------
+	// 不要求安全链接
 	httpClient.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
+	// ------------------------------------------------
+	if len(_proxySettings) == 0 {
+		// 无需设置代理
+		return httpClient, nil
+	}
+	// ------------------------------------------------
+	if proxySettings.UseSocks5OrHttpProxy == false {
+		// http 代理
+		if HttpProxyAddress != "" {
+			httpClient.SetProxy(HttpProxyAddress)
+		} else {
+			httpClient.RemoveProxy()
+		}
+	} else {
+		// socket5 代理
+		dialer, err := proxy.SOCKS5("tcp", socket5ProxyAddress, nil, proxy.Direct)
+		if err != nil {
+			return nil, err
+		}
+		dialContext := func(ctx context.Context, network, address string) (net.Conn, error) {
+			return dialer.Dial(network, address)
+		}
+		transport := &http.Transport{DialContext: dialContext, DisableKeepAlives: true}
+		httpClient.SetTransport(transport)
+	}
 
-	return httpClient
+	return httpClient, nil
 }
 
-func getPublicIP(inputSite string, queue *settings.TaskQueue, _proxySettings ...*settings.ProxySettings) string {
+func getPublicIP(inputSite string, _proxySettings ...*settings.ProxySettings) string {
 
 	var client *resty.Client
-	client = NewHttpClient(_proxySettings...)
-
-	targetSite := ""
-	if queue.CheckPublicIPTargetSite != "" {
-		targetSite = queue.CheckPublicIPTargetSite
-	} else {
-		targetSite = inputSite
+	client, err := NewHttpClient(_proxySettings...)
+	if err != nil {
+		return ""
 	}
-
-	response, err := client.R().Get(targetSite)
+	response, err := client.R().Get(inputSite)
 	if err != nil {
 		return ""
 	}
@@ -98,18 +123,29 @@ func getPublicIP(inputSite string, queue *settings.TaskQueue, _proxySettings ...
 
 func GetPublicIP(log *logrus.Logger, queue *settings.TaskQueue, _proxySettings ...*settings.ProxySettings) string {
 
-	publicIPSites := []string{
-		"https://api.ipify.org/",
+	defPublicIPSites := []string{
 		"https://myip.biturl.top/",
 		"https://ip4.seeip.org/",
 		"https://ipecho.net/plain",
 		"https://api-ipv4.ip.sb/ip",
+		"https://api.ipify.org/",
 		"http://myexternalip.com/raw",
 	}
 
-	for i, publicIPSite := range publicIPSites {
+	customPublicIPSites := make([]string, 0)
+	if queue.CheckPublicIPTargetSite != "" {
+		// 自定义了公网IP查询网站
+		tSites := strings.Split(queue.CheckPublicIPTargetSite, ";")
+		if tSites != nil && len(tSites) > 0 {
+			customPublicIPSites = append(customPublicIPSites, tSites...)
+		}
+	} else {
+		customPublicIPSites = append(customPublicIPSites, defPublicIPSites...)
+	}
+
+	for i, publicIPSite := range customPublicIPSites {
 		log.Debugln("[GetPublicIP]", i, publicIPSite)
-		publicIP := getPublicIP(publicIPSite, queue, _proxySettings...)
+		publicIP := getPublicIP(publicIPSite, _proxySettings...)
 
 		matcheds := regex_things.ReMatchIP.FindAllString(publicIP, -1)
 
@@ -123,18 +159,13 @@ func GetPublicIP(log *logrus.Logger, queue *settings.TaskQueue, _proxySettings .
 
 // DownFile 从指定的 url 下载文件
 func DownFile(l *logrus.Logger, urlStr string, _proxySettings ...*settings.ProxySettings) ([]byte, string, error) {
-	var proxySettings *settings.ProxySettings
-	if len(_proxySettings) > 0 {
-		proxySettings = _proxySettings[0]
-	}
 
+	var err error
 	var httpClient *resty.Client
-	if proxySettings != nil {
-		httpClient = NewHttpClient(proxySettings)
-	} else {
-		httpClient = NewHttpClient()
+	httpClient, err = NewHttpClient(_proxySettings...)
+	if err != nil {
+		return nil, "", err
 	}
-
 	resp, err := httpClient.R().Get(urlStr)
 	if err != nil {
 		return nil, "", err

+ 6 - 1
internal/pkg/my_util/util_test.go

@@ -34,5 +34,10 @@ func TestGetRestOfDaySec(t *testing.T) {
 func TestGetPublicIP(t *testing.T) {
 
 	got := GetPublicIP(log_helper.GetLogger(), settings.NewTaskQueue())
-	println(got)
+	println("NoProxy:", got)
+
+	got = GetPublicIP(log_helper.GetLogger(), settings.NewTaskQueue(),
+		settings.NewProxySettings(true, false, "",
+			true, "127.0.0.1:10808"))
+	println("UseProxy", got)
 }

+ 10 - 3
internal/pkg/settings/proxy_settings.go

@@ -1,7 +1,14 @@
 package settings
 
 type ProxySettings struct {
-	UseHttpProxy     bool   `json:"use_http_proxy"`     // 是否使用 http 代理
-	HttpProxyAddress string `json:"http_proxy_address"` // Http 代理地址,内网
-	Referer          string `json:"-"`                  // 可能下载文件的时候需要设置
+	UseSocks5OrHttpProxy bool   `json:"use_socks5_or_http_proxy"` // 是使用 socks5(true) 还是 http(false) 代理,默认是 http
+	UseHttpProxy         bool   `json:"use_http_proxy"`           // 是否使用 http 代理
+	HttpProxyAddress     string `json:"http_proxy_address"`       // Http 代理地址,内网
+	UseSocks5Proxy       bool   `json:"use_socks5_proxy"`         // 是否使用 socks5 代理
+	Socks5ProxyAddress   string `json:"socks5_proxy_address"`     // Socks5 代理地址,内网
+	Referer              string `json:"-"`                        // 可能下载文件的时候需要设置
+}
+
+func NewProxySettings(useSocks5OrHttpProxy bool, useHttpProxy bool, httpProxyAddress string, useSocks5Proxy bool, socks5ProxyAddress string) *ProxySettings {
+	return &ProxySettings{UseSocks5OrHttpProxy: useSocks5OrHttpProxy, UseHttpProxy: useHttpProxy, HttpProxyAddress: httpProxyAddress, UseSocks5Proxy: useSocks5Proxy, Socks5ProxyAddress: socks5ProxyAddress}
 }

+ 8 - 8
internal/pkg/settings/task_queue.go

@@ -1,13 +1,13 @@
 package settings
 
 type TaskQueue struct {
-	MaxRetryTimes           int    `json:"max_retry_times" default:"3"`                                      // 单个任务失败后,最大重试次数,超过后会降一级
-	OneJobTimeOut           int    `json:"one_job_time_out" default:"300"`                                   // 单个任务的超时时间 5 * 60 s
-	Interval                int    `json:"interval" default:"10"`                                            // 任务的间隔,单位 s,这里会有一个限制,不允许太快,然后会做一定的随机时间范围,当前值 x ~ 2*x 之内随机
-	ExpirationTime          int    `json:"expiration_time"  default:"90"`                                    // 单位天。1. 一个视频的 CreateTime 在这个时间范围内,都会被下载字幕(除非已经观看跳过启用了)。2. 如果下载失败的任务,AddTime 超过了这个时间,那么就标记为 Failed
-	DownloadSubDuringXDays  int    `json:"download_sub_during_x_days" default:"7"`                           // 如果创建了 x 天,且有内置的中文字幕,那么也不进行下载了
-	OneSubDownloadInterval  int    `json:"one_sub_download_interval" default:"12"`                           // 一个字幕下载的间隔(单位 h),不然老是一个循环。对比的基准是 OneJob 的 UpdateTime
-	CheckPublicIPTargetSite string `json:"check_pulic_ip_target_site" default:"http://myexternalip.com/raw"` // 检测本机外网 IP 的目标地址,必须是返回直接的 IP 字符串,不需要解析
+	MaxRetryTimes           int    `json:"max_retry_times" default:"3"`            // 单个任务失败后,最大重试次数,超过后会降一级
+	OneJobTimeOut           int    `json:"one_job_time_out" default:"300"`         // 单个任务的超时时间 5 * 60 s
+	Interval                int    `json:"interval" default:"10"`                  // 任务的间隔,单位 s,这里会有一个限制,不允许太快,然后会做一定的随机时间范围,当前值 x ~ 2*x 之内随机
+	ExpirationTime          int    `json:"expiration_time"  default:"90"`          // 单位天。1. 一个视频的 CreateTime 在这个时间范围内,都会被下载字幕(除非已经观看跳过启用了)。2. 如果下载失败的任务,AddTime 超过了这个时间,那么就标记为 Failed
+	DownloadSubDuringXDays  int    `json:"download_sub_during_x_days" default:"7"` // 如果创建了 x 天,且有内置的中文字幕,那么也不进行下载了
+	OneSubDownloadInterval  int    `json:"one_sub_download_interval" default:"12"` // 一个字幕下载的间隔(单位 h),不然老是一个循环。对比的基准是 OneJob 的 UpdateTime
+	CheckPublicIPTargetSite string `json:"check_pulic_ip_target_site" default:""`  // 检测本机外网 IP 的目标地址,必须是返回直接的 IP 字符串,不需要解析。; 分割
 }
 
 func NewTaskQueue() *TaskQueue {
@@ -18,6 +18,6 @@ func NewTaskQueue() *TaskQueue {
 		ExpirationTime:          90,
 		DownloadSubDuringXDays:  7,
 		OneSubDownloadInterval:  12,
-		CheckPublicIPTargetSite: "http://myexternalip.com/raw",
+		CheckPublicIPTargetSite: "",
 	}
 }