Skip to content

Commit

Permalink
add support for HTTP(S)_PROXY env
Browse files Browse the repository at this point in the history
  • Loading branch information
sagan committed Dec 19, 2023
1 parent 5e3482e commit dfaef01
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 17 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,14 @@ cookie = "cookie_here" # 浏览器 F12 获取的网站 cookie

推荐使用“方式 1”。程序内置了对大部分国内 NexusPHP PT 站点的支持。站点 type 通常为 PT 网站域名的主体部分(不含次级域名和 TLD 部分),例如 BTSCHOOL ( https://pt.btschool.club/ )的站点 type 是 btschool。部分 PT 网站也可以使用别名(alias)配置,例如 M-TEAM ( https://kp.m-team.cc/ )在本程序配置文件里的 type 设为 "m-team" 或 "mteam" 均可。运行 ```ptool sites``` 查看所有本程序内置支持的 PT 站点列表。本程序没有内置支持的 PT 站点必须通过“方式 2”配置。 (注:部分非 NP 架构站点本程序目前只支持自动辅种、查看站点状态,暂不支持刷流、搜索站点种子等功能)

参考程序代码根目录下的 ```ptool.example.toml``````ptool.example.yaml``` 示例配置文件了解所有可用的配置项。

配置好站点后,使用 ```ptool status <site> -t``` 测试(```<site>```参数为站点的 name)。如果配置正确且 Cookie 有效,会显示站点当前登录用户的状态信息和网站最新种子列表。

程序支持自动与浏览器同步站点 Cookies 或导入站点信息。详细信息请参考本文档 "cookiecloud" 命令说明部分。

参考程序代码根目录下的 ```ptool.example.toml``````ptool.example.yaml``` 示例配置文件了解常用配置项信息。

查看程序代码 [config/config.go](https://github.com/sagan/ptool/blob/master/config/config.go) 文件里的 type ConfigStruct struct 获取全部可配置项信息。

## 程序功能

所有功能通过启动程序时传入的第一个”命令“参数区分:
Expand Down Expand Up @@ -514,6 +516,16 @@ ptool cookiecloud get <site>...

默认以 Http 请求 "Cookie" 头格式显示 Cookies。如果指定 ```--format js``` 参数,则会以 JavaScript 的 "document.cookie='';" 代码段格式显示 Cookies,可以直接将输出结果复制到浏览器 F12 开发者工具 Console 里执行以导入 Cookies。

### 查看内置支持站点信息 (sites)

```
# 显示所有内置支持的站点列表。ptool.toml 配置文件里将 [[site]] 配置块的 type 设为站点的 Type 或 Alias。
ptool sites
# 显示对应站点在本程序内部使用的详细配置参数。参数为站点的 Type 或 Alias。
ptool sites show mteam
```

### 交互式终端 (shell)

```ptool shell``` 可以启动一个交互式的 shell 终端环境。终端里可以运行所有 ptool 支持的命令。命令和命令参数输入支持完整的自动补全。
Expand Down
22 changes: 16 additions & 6 deletions cmd/cookiecloud/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import (
"net/url"
"sort"
"strings"
"time"

"github.com/sagan/ptool/config"
"github.com/sagan/ptool/util"
"github.com/sagan/ptool/util/crypto"
)
Expand Down Expand Up @@ -35,23 +37,31 @@ type CookiecloudData struct {
Cookie_data map[string][]map[string]any `json:"cookie_data"`
}

func GetCookiecloudData(server string, uuid string, password string, proxy string) (*CookiecloudData, error) {
// If proxy is empty, will try to get proxy from HTTP_PROXY & HTTPS_PROXY envs.
func GetCookiecloudData(server string, uuid string, password string,
proxy string, timeout int64) (*CookiecloudData, error) {
if server == "" || uuid == "" || password == "" {
return nil, fmt.Errorf("all params of server,uuid,password must be provided")
}
if !strings.HasSuffix(server, "/") {
server += "/"
}
var httpClient *http.Client
if proxy == "" {
proxy = util.ParseProxyFromEnv(server)
}
if timeout == 0 {
timeout = config.DEFAULT_COOKIECLOUD_TIMEOUT
}
httpClient := &http.Client{
Timeout: time.Duration(timeout) * time.Second,
}
if proxy != "" {
proxyUrl, err := url.Parse(proxy)
if err != nil {
return nil, fmt.Errorf("failed to parse proxy %s: %v", proxy, err)
}
httpClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
},
httpClient.Transport = &http.Transport{
Proxy: http.ProxyURL(proxyUrl),
}
}
var data *CookieCloudBody
Expand Down
3 changes: 2 additions & 1 deletion cmd/cookiecloud/get/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ func get(cmd *cobra.Command, args []string) error {
}
cookiecloudDatas := []cookiecloud.Ccdata_struct{}
for _, profile := range cookiecloudProfiles {
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password, profile.Proxy)
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password,
profile.Proxy, profile.Timeoout)
if err != nil {
log.Errorf("Cookiecloud server %s (uuid %s) connection failed: %v\n", profile.Server, profile.Uuid, err)
cntError++
Expand Down
3 changes: 2 additions & 1 deletion cmd/cookiecloud/importsites/importsites.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ func importsites(cmd *cobra.Command, args []string) error {
}
cookiecloudDatas := []cookiecloud.Ccdata_struct{}
for _, profile := range cookiecloudProfiles {
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password, profile.Proxy)
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password,
profile.Proxy, profile.Timeoout)
if err != nil {
log.Errorf("Cookiecloud server %s (uuid %s) connection failed: %v\n", profile.Server, profile.Uuid, err)
cntError++
Expand Down
3 changes: 2 additions & 1 deletion cmd/cookiecloud/status/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ func status(cmd *cobra.Command, args []string) error {
return fmt.Errorf("no cookiecloud profile specified or found")
}
for _, profile := range cookiecloudProfiles {
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password, profile.Proxy)
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password,
profile.Proxy, profile.Timeoout)
if err != nil {
fmt.Printf("✕cookiecloud server %s (uuid %s) test failed: %v\n",
util.ParseUrlHostname(profile.Server), profile.Uuid, err)
Expand Down
3 changes: 2 additions & 1 deletion cmd/cookiecloud/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ func sync(cmd *cobra.Command, args []string) error {
}
cookiecloudDatas := []cookiecloud.Ccdata_struct{}
for _, profile := range cookiecloudProfiles {
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password, profile.Proxy)
data, err := cookiecloud.GetCookiecloudData(profile.Server, profile.Uuid, profile.Password,
profile.Proxy, profile.Timeoout)
if err != nil {
log.Errorf("Cookiecloud server %s (uuid %s) connection failed: %v\n", profile.Server, profile.Uuid, err)
cntError++
Expand Down
5 changes: 4 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
STATS_FILENAME = "ptool_stats.txt"
HISTORY_FILENAME = "ptool_history"

DEFAULT_TIMEOUT = int64(5)
DEFAULT_SHELL_MAX_SUGGESTIONS = int64(5)
DEFAULT_SHELL_MAX_HISTORY = int64(500)
DEFAULT_SITE_TIMEZONE = "Asia/Shanghai"
Expand All @@ -34,11 +35,12 @@ const (
DEFAULT_CLIENT_BRUSH_MAX_TORRENTS = int64(9999)
DEFAULT_CLIENT_BRUSH_MIN_RATION = float64(0.2)
DEFAULT_CLIENT_BRUSH_DEFAULT_UPLOAD_SPEED_LIMIT = int64(10 * 1024 * 1024)
DEFAULT_SITE_TIMEOUT = int64(5)
DEFAULT_SITE_TIMEOUT = DEFAULT_TIMEOUT
DEFAULT_SITE_BRUSH_TORRENT_MIN_SIZE_LIMIT = int64(0)
DEFAULT_SITE_BRUSH_TORRENT_MAX_SIZE_LIMIT = int64(1024 * 1024 * 1024 * 1024 * 1024) // 1PB, that's say, unlimited
DEFAULT_SITE_TORRENT_UPLOAD_SPEED_LIMIT = int64(10 * 1024 * 1024)
DEFAULT_SITE_FLOW_CONTROL_INTERVAL = int64(3)
DEFAULT_COOKIECLOUD_TIMEOUT = DEFAULT_TIMEOUT
)

type CookiecloudConfigStruct struct {
Expand All @@ -49,6 +51,7 @@ type CookiecloudConfigStruct struct {
Password string `yaml:"password"`
Proxy string `yaml:"proxy"`
Sites []string `yaml:"sites"`
Timeoout int64 `yaml:"timeout"`
Comment string `yaml:"comment"`
}

Expand Down
9 changes: 5 additions & 4 deletions ptool.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ iyuuToken = '' # iyuu token。用于自动辅种功能
#siteTimeout = 5 # 访问网站超时时间(秒)
#siteJa3 = "" # 设置访问站点时使用的 TLS ja3 指纹。默认使用最新稳定版 Chrome on Windows x64 en-US 的
#siteH2Fingerprint = "" # 设置访问站点时使用的 HTTP2 指纹(akamai_fingerprint)。默认使用 Chrome 的
#siteProxy = '' # 使用代理访问 PT 站点(不适用于访问 BT 客户端)。格式为 'http://127.0.0.1:1080'. 所有支持的代理协议: https://github.com/Noooste/azuretls-client?tab=readme-ov-file#proxy
#siteProxy = '' # 使用代理访问 PT 站点(不适用于访问 BT 客户端)。格式为 'http://127.0.0.1:1080'所有支持的代理协议: https://github.com/Noooste/azuretls-client?tab=readme-ov-file#proxy . 也支持通过 HTTP_PROXY & HTTPS_PROXY 环境变量设置代理
#siteUserAgent = '' # 所有站点默认使用的 ua。默认使用 Chrome 的
#brushEnableStats = false # 启用刷流统计功能
#hushshell = false # 如果设为 true, 启动 ptool shell 时将不显示欢迎信息
#shellMaxSuggestions = 5 # ptool shell 自动补全显示建议数量。设为 0 禁用
#shellMaxHistory = 500 # ptool shell 命令历史记录保存数量。设为 0 禁用
#siteNoDefaultHttpHeaders = false # 如果设为 true, 访问站点时禁用默认设置的模仿 Chrome 的 http 请求头

# 自定义访问站点时设置的 http 请求头。如果值设为空,删除对应header
#[siteHttpHeaders]
#'Cache-Control' = 'no-cache'
# 自定义访问站点时设置的 http 请求头。如果值设为空,删除对应 header
#siteHttpHeaders = [
# ['Cache-Control', 'no-cache']
#]

# 完整支持 qBittorrent v4.1+ (推荐使用 qb v4.4+)
[[clients]]
Expand Down
3 changes: 3 additions & 0 deletions site/site.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ func CreateSiteHttpClient(siteConfig *config.SiteConfigStruct, globalConfig *con
if siteConfig.Proxy != "" {
proxy = siteConfig.Proxy
}
if proxy == "" {
proxy = util.ParseProxyFromEnv(siteConfig.Url)
}
// 暂时默认设为 insecure。因为 azuretls 似乎对某些站点(如 byr)的 TLS 证书校验有问题。
insecure := true
if globalConfig.SiteSecure {
Expand Down
46 changes: 46 additions & 0 deletions util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/hex"
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
"reflect"
Expand Down Expand Up @@ -273,3 +274,48 @@ func AskYesNoConfirm(prompt string) bool {
func First[T1 any, T2 any](v T1, args ...T2) T1 {
return v
}

// Parse standard HTTP_PROXY, HTTPS_PROXY, NO_PROXY (and lowercase versions) envs, return proxy for urlStr.
// If urlStr is empty, return default http(s) proxy, prefer HTTPS_PROXY over HTTP_PROXY.
// However, it currently does not support CIDR style IP range value in NO_PROXY.
func ParseProxyFromEnv(urlStr string) string {
var noProxyEnv, httpProxyEnv, httpsProxyEnv string
if os.Getenv("NO_PROXY") != "" {
noProxyEnv = os.Getenv("NO_PROXY")
} else if os.Getenv("no_proxy") != "" {
noProxyEnv = os.Getenv("no_proxy")
}
if os.Getenv("HTTP_PROXY") != "" {
httpProxyEnv = os.Getenv("HTTP_PROXY")
} else if os.Getenv("http_proxy") != "" {
httpProxyEnv = os.Getenv("http_proxy")
}
if os.Getenv("HTTPS_PROXY") != "" {
httpsProxyEnv = os.Getenv("HTTPS_PROXY")
} else if os.Getenv("https_proxy") != "" {
httpsProxyEnv = os.Getenv("https_proxy")
}
if urlStr == "" {
if httpsProxyEnv != "" {
return httpsProxyEnv
}
return httpProxyEnv
}
urlObj, err := url.Parse(urlStr)
if err != nil {
if httpsProxyEnv != "" {
return httpsProxyEnv
}
return httpProxyEnv
}
if urlObj.Host != "" {
if noProxys := strings.Split(noProxyEnv, ","); slices.Index(noProxys, urlObj.Host) != -1 {
return ""
}
}
if urlObj.Scheme == "http" {
return httpProxyEnv
} else {
return httpsProxyEnv
}
}

0 comments on commit dfaef01

Please sign in to comment.