feat: support multi-threaded download
This commit is contained in:
1 parent
b352181270
commit
53636d465e
11 files changed
+636
-462
No files matched your search
@@ -0,0 +1,60 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"wx_channel/pkg/decrypt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
file_path string
|
||||
video_decrypt_key2 int
|
||||
)
|
||||
var decrypt_cmd = &cobra.Command{
|
||||
Use: "decrypt",
|
||||
Short: "解密视频",
|
||||
Long: "使用 key 对本地加密视频进行解密",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "decrypt" {
|
||||
return
|
||||
}
|
||||
decrypt_command(DecryptCOmmandArgs{
|
||||
Filepath: file_path,
|
||||
DecryptKey: video_decrypt_key2,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
decrypt_cmd.Flags().StringVar(&file_path, "filepath", "", "视频地址(必需)")
|
||||
decrypt_cmd.Flags().IntVar(&video_decrypt_key2, "key", 0, "解密密钥(必需)")
|
||||
decrypt_cmd.MarkFlagRequired("filepath")
|
||||
|
||||
root_cmd.AddCommand(decrypt_cmd)
|
||||
}
|
||||
|
||||
type DecryptCOmmandArgs struct {
|
||||
Filepath string
|
||||
DecryptKey int
|
||||
}
|
||||
|
||||
func decrypt_command(args DecryptCOmmandArgs) {
|
||||
fmt.Printf("开始对文件解密 %s\n", args.Filepath)
|
||||
length := uint32(131072)
|
||||
key := uint64(args.DecryptKey)
|
||||
data, err := os.ReadFile(args.Filepath)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]读取已下载的文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
decrypt.DecryptData(data, length, key)
|
||||
err = os.WriteFile(args.Filepath, data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]写入文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("解密完成 %s\n", args.Filepath)
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"wx_channel/pkg/decrypt"
|
||||
"wx_channel/pkg/download"
|
||||
)
|
||||
|
||||
var (
|
||||
video_url string
|
||||
filename string
|
||||
video_decrypt_key int
|
||||
)
|
||||
|
||||
var download_cmd = &cobra.Command{
|
||||
Use: "download",
|
||||
Short: "下载视频",
|
||||
Long: "从指定URL下载视频文件",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "download" {
|
||||
return
|
||||
}
|
||||
download_command(DownloadCommandArgs{
|
||||
URL: video_url,
|
||||
DecryptKey: video_decrypt_key,
|
||||
Filename: filename,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
now := int(time.Now().Unix())
|
||||
download_cmd.Flags().StringVar(&video_url, "url", "", "视频URL(必需)")
|
||||
download_cmd.Flags().IntVar(&video_decrypt_key, "key", 0, "解密密钥(未加密的视频不用传该参数)")
|
||||
download_cmd.Flags().StringVar(&filename, "filename", strconv.Itoa(now)+".mp4", "下载后的文件名")
|
||||
download_cmd.MarkFlagRequired("url")
|
||||
|
||||
root_cmd.AddCommand(download_cmd)
|
||||
}
|
||||
|
||||
type DownloadCommandArgs struct {
|
||||
URL string
|
||||
Filename string
|
||||
DecryptKey int
|
||||
}
|
||||
|
||||
func download_command(args DownloadCommandArgs) {
|
||||
url := args.URL
|
||||
homedir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]获取下载路径失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
tmp_filename := "tmp_wx_" + strconv.Itoa(int(time.Now().Unix()))
|
||||
tmp_dest_filepath := filepath.Join(homedir, "Downloads", tmp_filename)
|
||||
dest_filepath := filepath.Join(homedir, "Downloads", args.Filename)
|
||||
|
||||
if err := download.MultiThreadingDownload(url, 4, tmp_dest_filepath, tmp_dest_filepath); err != nil {
|
||||
fmt.Printf("[ERROR]%v\n", err.Error())
|
||||
return
|
||||
}
|
||||
// elapsed := time.Since(start_time)
|
||||
// speed := float64(file_size) / elapsed.Seconds() / 1024 / 1024
|
||||
|
||||
fmt.Printf("\n临时文件下载完成!\n")
|
||||
// fmt.Printf("文件大小: %.2f MB\n", float64(file_size)/1024/1024)
|
||||
// fmt.Printf("耗时: %.2f 秒\n", elapsed.Seconds())
|
||||
// fmt.Printf("平均速度: %.2f MB/s\n", speed)
|
||||
fmt.Println()
|
||||
if args.DecryptKey != 0 {
|
||||
fmt.Printf("开始对临时文件解密 %s\n", tmp_dest_filepath)
|
||||
length := uint32(131072)
|
||||
key := uint64(args.DecryptKey)
|
||||
data, err := os.ReadFile(tmp_dest_filepath)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]读取临时文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
decrypt.DecryptData(data, length, key)
|
||||
err = os.WriteFile(dest_filepath, data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]写入文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("删除临时文件 %s\n", tmp_dest_filepath)
|
||||
if err := os.Remove(tmp_dest_filepath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println("[ERROR]临时文件不存在")
|
||||
} else if os.IsPermission(err) {
|
||||
fmt.Println("[ERROR]没有权限删除临时文件")
|
||||
} else {
|
||||
fmt.Printf("[ERROR]临时文件删除失败 %v\n", err.Error())
|
||||
}
|
||||
}
|
||||
fmt.Printf("解密完成,文件路径为 %s\n", dest_filepath)
|
||||
return
|
||||
}
|
||||
fmt.Printf("下载完成,文件路径为 %s\n", dest_filepath)
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"wx_channel/internal/application"
|
||||
"wx_channel/internal/handler"
|
||||
"wx_channel/pkg/certificate"
|
||||
"wx_channel/pkg/echo"
|
||||
"wx_channel/pkg/proxy"
|
||||
)
|
||||
|
||||
var (
|
||||
device string
|
||||
port int
|
||||
debug bool
|
||||
version string
|
||||
files *application.BizFiles
|
||||
cert_file_name string
|
||||
)
|
||||
|
||||
var root_cmd = &cobra.Command{
|
||||
Use: "wx_video_download",
|
||||
Short: "启动下载程序",
|
||||
Long: "\n启动后将对网络请求进行代理,在微信视频号详情页面注入下载按钮",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
root_command(RootCommandArg{
|
||||
Device: device,
|
||||
Port: port,
|
||||
Debug: debug,
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
root_cmd.Flags().StringVar(&device, "dev", "", "代理服务器网络设备")
|
||||
root_cmd.Flags().IntVar(&port, "port", 2023, "代理服务器端口")
|
||||
root_cmd.Flags().BoolVar(&debug, "debug", false, "是否开启调试")
|
||||
|
||||
}
|
||||
|
||||
func Initialize(app_ver string, cert_file_name string, files *application.BizFiles) {
|
||||
version = app_ver
|
||||
cert_file_name = cert_file_name
|
||||
files = files
|
||||
}
|
||||
func Register(cmd *cobra.Command) {
|
||||
root_cmd.AddCommand(cmd)
|
||||
}
|
||||
func Execute() error {
|
||||
cobra.MousetrapHelpText = ""
|
||||
|
||||
return root_cmd.Execute()
|
||||
}
|
||||
|
||||
type RootCommandArg struct {
|
||||
Device string
|
||||
Port int
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func root_command(args RootCommandArg) {
|
||||
os_env := runtime.GOOS
|
||||
|
||||
signal_chan := make(chan os.Signal, 1)
|
||||
// Notify the signal channel on SIGINT (Ctrl+C) and SIGTERM
|
||||
signal.Notify(signal_chan, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
sig := <-signal_chan
|
||||
fmt.Printf("\n正在关闭服务...%v\n\n", sig)
|
||||
arg := proxy.ProxySettings{
|
||||
Device: args.Device,
|
||||
Hostname: "127.0.0.1",
|
||||
Port: strconv.Itoa(args.Port),
|
||||
}
|
||||
err := proxy.DisableProxy(arg)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ 关闭系统代理失败: %v\n", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
fmt.Printf("\nv" + version)
|
||||
fmt.Printf("\n问题反馈 https://github.com/ltaoo/wx_channels_download/issues\n")
|
||||
existing, err1 := certificate.CheckHasCertificate(cert_file_name)
|
||||
if err1 != nil {
|
||||
fmt.Printf("\nERROR %v\v", err1.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
if !existing {
|
||||
fmt.Printf("\n\n正在安装证书...\n")
|
||||
err := certificate.InstallCertificate(files.CertFile)
|
||||
time.Sleep(3 * time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
}
|
||||
biz := application.NewBiz(version, files)
|
||||
echo, err := echo.NewEcho(files.CertFile, files.PrivateKeyFile)
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
echo.SetHTTPHandler(handler.HandleHttpRequestEcho(biz))
|
||||
// Sunny.SetPort(args.Port).Start()
|
||||
go func() {
|
||||
server := &http.Server{
|
||||
Addr: ":" + strconv.Itoa(port),
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
echo.ServeHTTP(w, r)
|
||||
}),
|
||||
}
|
||||
fmt.Printf("Proxy server listening on :%v\n", port)
|
||||
err := server.ListenAndServe()
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
}
|
||||
}()
|
||||
|
||||
if os_env == "windows" {
|
||||
// ok := Sunny.OpenDrive(true)
|
||||
// if !ok {
|
||||
// fmt.Printf("\nERROR 启动进程代理失败,检查是否以管理员身份运行\n")
|
||||
// fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
// select {}
|
||||
// }
|
||||
// Sunny.ProcessAddName("WeChatAppEx.exe")
|
||||
err = proxy.EnableProxy(proxy.ProxySettings{
|
||||
Device: args.Device,
|
||||
Hostname: "127.0.0.1",
|
||||
Port: strconv.Itoa(args.Port),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR 设置代理失败 %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
} else {
|
||||
err = proxy.EnableProxy(proxy.ProxySettings{
|
||||
Device: args.Device,
|
||||
Hostname: "127.0.0.1",
|
||||
Port: strconv.Itoa(args.Port),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR 设置代理失败 %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
}
|
||||
color.Green(fmt.Sprintf("\n\n服务已正确启动,请打开需要下载的视频号页面进行下载"))
|
||||
fmt.Println("\n\n服务正在运行,按 Ctrl+C 退出...")
|
||||
select {}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"wx_channel/pkg/certificate"
|
||||
"wx_channel/pkg/proxy"
|
||||
)
|
||||
|
||||
var uninstall_certificate_cmd = &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Short: "删除证书",
|
||||
Long: "删除初始化时自动安装的证书",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "uninstall" {
|
||||
return
|
||||
}
|
||||
uninstall_certificate_command(UninstallCertificateCommandArgs{})
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
root_cmd.AddCommand(uninstall_certificate_cmd)
|
||||
}
|
||||
|
||||
type UninstallCertificateCommandArgs struct {
|
||||
}
|
||||
|
||||
func uninstall_certificate_command(args UninstallCertificateCommandArgs) {
|
||||
settings := proxy.ProxySettings{}
|
||||
if err := proxy.DisableProxy(settings); err != nil {
|
||||
fmt.Printf("\nERROR 取消代理失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
if err := certificate.UninstallCertificate(cert_file_name); err != nil {
|
||||
fmt.Printf("\nERROR 删除根证书失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
color.Green(fmt.Sprintf("\n\n删除根证书 '%v' 成功\n", cert_file_name))
|
||||
}
|
||||
@@ -16,17 +16,15 @@ import (
|
||||
"wx_channel/pkg/proxy"
|
||||
)
|
||||
|
||||
var RootCertificateName = "SunnyNet"
|
||||
|
||||
type BizFiles struct {
|
||||
Cert []byte
|
||||
PrivateKey []byte
|
||||
JSFileSave []byte
|
||||
JSZip []byte
|
||||
JSPageSpy1 []byte
|
||||
JSPageSpy2 []byte
|
||||
JSError []byte
|
||||
JSMain []byte
|
||||
CertFile []byte
|
||||
PrivateKeyFile []byte
|
||||
JSFileSaver []byte
|
||||
JSZip []byte
|
||||
JSPageSpy1 []byte
|
||||
JSPageSpy2 []byte
|
||||
JSError []byte
|
||||
JSMain []byte
|
||||
}
|
||||
|
||||
type Biz struct {
|
||||
@@ -35,36 +33,27 @@ type Biz struct {
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func NewBiz(version string, cert []byte, private_key []byte, js_file_save []byte, js_zip []byte, js_page_spy1 []byte, js_page_spy2 []byte, js_error []byte, js_main []byte) *Biz {
|
||||
func NewBiz(version string, files *BizFiles) *Biz {
|
||||
return &Biz{
|
||||
Version: version,
|
||||
Files: &BizFiles{
|
||||
Cert: cert,
|
||||
PrivateKey: private_key,
|
||||
JSFileSave: js_file_save,
|
||||
JSZip: js_zip,
|
||||
JSPageSpy1: js_page_spy1,
|
||||
JSPageSpy2: js_page_spy2,
|
||||
JSMain: js_main,
|
||||
JSError: js_error,
|
||||
},
|
||||
Files: files,
|
||||
}
|
||||
}
|
||||
func (a *Biz) SetDebug(debug bool) {
|
||||
a.Debug = debug
|
||||
}
|
||||
|
||||
func (a *Biz) UninstallCertificate() {
|
||||
func (a *Biz) UninstallCertificate(cert_file_name string) {
|
||||
settings := proxy.ProxySettings{}
|
||||
if err := proxy.DisableProxy(settings); err != nil {
|
||||
fmt.Printf("\nERROR 取消代理失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
if err := certificate.UninstallCertificate(RootCertificateName); err != nil {
|
||||
if err := certificate.UninstallCertificate(cert_file_name); err != nil {
|
||||
fmt.Printf("\nERROR 删除根证书失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
color.Green(fmt.Sprintf("\n\n删除根证书 '%v' 成功\n", RootCertificateName))
|
||||
color.Green(fmt.Sprintf("\n\n删除根证书 '%v' 成功\n", cert_file_name))
|
||||
}
|
||||
|
||||
type DecryptCOmmandArgs struct {
|
||||
|
||||
@@ -3,32 +3,16 @@ package main
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"wx_channel/cmd"
|
||||
"wx_channel/internal/application"
|
||||
"wx_channel/internal/handler"
|
||||
"wx_channel/pkg/certificate"
|
||||
"wx_channel/pkg/decrypt"
|
||||
"wx_channel/pkg/echo"
|
||||
"wx_channel/pkg/proxy"
|
||||
)
|
||||
|
||||
//go:embed certs/SunnyRoot.cer
|
||||
var cert_data []byte
|
||||
var cert_file []byte
|
||||
|
||||
//go:embed certs/private.key
|
||||
var private_key_data []byte
|
||||
var private_key_file []byte
|
||||
|
||||
//go:embed lib/FileSaver.min.js
|
||||
var js_file_saver []byte
|
||||
@@ -48,338 +32,24 @@ var js_error []byte
|
||||
//go:embed inject/main.js
|
||||
var js_main []byte
|
||||
|
||||
var version = "250913"
|
||||
var DefaultPort = 2023
|
||||
var RootCertificateName = "SunnyNet"
|
||||
var AppVer = "250913"
|
||||
|
||||
func main() {
|
||||
cobra.MousetrapHelpText = ""
|
||||
|
||||
var (
|
||||
device string
|
||||
port int
|
||||
debug bool
|
||||
)
|
||||
|
||||
root_cmd := &cobra.Command{
|
||||
Use: "wx_video_download",
|
||||
Short: "启动下载程序",
|
||||
Long: "启动后将对网络请求进行代理,在微信视频号详情页面注入下载按钮",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
root_command(RootCommandArg{
|
||||
Device: device,
|
||||
Port: port,
|
||||
Debug: debug,
|
||||
})
|
||||
},
|
||||
files := &application.BizFiles{
|
||||
CertFile: cert_file,
|
||||
PrivateKeyFile: private_key_file,
|
||||
JSFileSaver: js_file_saver,
|
||||
JSZip: js_zip,
|
||||
JSPageSpy1: js_pagespy1,
|
||||
JSPageSpy2: js_pagespy2,
|
||||
JSMain: js_main,
|
||||
JSError: js_error,
|
||||
}
|
||||
root_cmd.Flags().StringVar(&device, "dev", "", "代理服务器网络设备")
|
||||
root_cmd.Flags().IntVar(&port, "port", DefaultPort, "代理服务器端口")
|
||||
root_cmd.Flags().BoolVar(&debug, "debug", false, "是否开启调试")
|
||||
|
||||
uninstall_certificate_cmd := &cobra.Command{
|
||||
Use: "uninstall",
|
||||
Short: "删除证书",
|
||||
Long: "删除初始化时自动安装的证书",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "uninstall" {
|
||||
return
|
||||
}
|
||||
uninstall_certificate_command(UninstallCertificateCommandArgs{})
|
||||
},
|
||||
}
|
||||
|
||||
var (
|
||||
video_url string
|
||||
filename string
|
||||
video_decrypt_key int
|
||||
)
|
||||
download_cmd := &cobra.Command{
|
||||
Use: "download",
|
||||
Short: "下载视频",
|
||||
Long: "从指定URL下载视频文件",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "download" {
|
||||
return
|
||||
}
|
||||
download_command(DownloadCommandArgs{
|
||||
URL: video_url,
|
||||
DecryptKey: video_decrypt_key,
|
||||
Filename: filename,
|
||||
})
|
||||
},
|
||||
}
|
||||
now := int(time.Now().Unix())
|
||||
download_cmd.Flags().StringVar(&video_url, "url", "", "视频URL(必需)")
|
||||
download_cmd.Flags().IntVar(&video_decrypt_key, "key", 0, "解密密钥(未加密的视频不用传该参数)")
|
||||
download_cmd.Flags().StringVar(&filename, "filename", strconv.Itoa(now)+".mp4", "下载后的文件名")
|
||||
download_cmd.MarkFlagRequired("url")
|
||||
|
||||
var (
|
||||
filepath string
|
||||
video_decrypt_key2 int
|
||||
)
|
||||
decrypt_cmd := &cobra.Command{
|
||||
Use: "decrypt",
|
||||
Short: "解密视频",
|
||||
Long: "使用 key 对本地加密视频进行解密",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
command := cmd.Name()
|
||||
if command != "decrypt" {
|
||||
return
|
||||
}
|
||||
decrypt_command(DecryptCOmmandArgs{
|
||||
Filepath: filepath,
|
||||
DecryptKey: video_decrypt_key2,
|
||||
})
|
||||
},
|
||||
}
|
||||
decrypt_cmd.Flags().StringVar(&filepath, "filepath", "", "视频地址(必需)")
|
||||
decrypt_cmd.Flags().IntVar(&video_decrypt_key2, "key", 0, "解密密钥(必需)")
|
||||
decrypt_cmd.MarkFlagRequired("filepath")
|
||||
|
||||
root_cmd.AddCommand(uninstall_certificate_cmd)
|
||||
root_cmd.AddCommand(download_cmd)
|
||||
root_cmd.AddCommand(decrypt_cmd)
|
||||
if err := root_cmd.Execute(); err != nil {
|
||||
cmd.Initialize(AppVer, RootCertificateName, files)
|
||||
if err := cmd.Execute(); err != nil {
|
||||
fmt.Printf("初始化失败 %v", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
}
|
||||
|
||||
type RootCommandArg struct {
|
||||
Device string
|
||||
Port int
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func root_command(args RootCommandArg) {
|
||||
os_env := runtime.GOOS
|
||||
|
||||
signal_chan := make(chan os.Signal, 1)
|
||||
// Notify the signal channel on SIGINT (Ctrl+C) and SIGTERM
|
||||
signal.Notify(signal_chan, syscall.SIGINT, syscall.SIGTERM)
|
||||
go func() {
|
||||
sig := <-signal_chan
|
||||
fmt.Printf("\n正在关闭服务...%v\n\n", sig)
|
||||
arg := proxy.ProxySettings{
|
||||
Device: args.Device,
|
||||
Hostname: "127.0.0.1",
|
||||
Port: strconv.Itoa(args.Port),
|
||||
}
|
||||
err := proxy.DisableProxy(arg)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ 关闭系统代理失败: %v\n", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
fmt.Printf("\nv" + version)
|
||||
fmt.Printf("\n问题反馈 https://github.com/ltaoo/wx_channels_download/issues\n")
|
||||
existing, err1 := certificate.CheckHasCertificate(RootCertificateName)
|
||||
if err1 != nil {
|
||||
fmt.Printf("\nERROR %v\v", err1.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
if !existing {
|
||||
fmt.Printf("\n\n正在安装证书...\n")
|
||||
err := certificate.InstallCertificate(cert_data)
|
||||
time.Sleep(3 * time.Second)
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
}
|
||||
biz := application.NewBiz(version, cert_data, private_key_data, js_file_saver, js_zip, js_pagespy1, js_pagespy2, js_error, js_main)
|
||||
echo, err := echo.NewEcho(cert_data, private_key_data)
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
echo.SetHTTPHandler(handler.HandleHttpRequestEcho(biz))
|
||||
// Sunny.SetPort(args.Port).Start()
|
||||
go func() {
|
||||
server := &http.Server{
|
||||
Addr: ":" + strconv.Itoa(DefaultPort),
|
||||
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
echo.ServeHTTP(w, r)
|
||||
}),
|
||||
}
|
||||
fmt.Printf("Proxy server listening on :%v\n", DefaultPort)
|
||||
err := server.ListenAndServe()
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
}
|
||||
}()
|
||||
|
||||
if os_env == "windows" {
|
||||
// ok := Sunny.OpenDrive(true)
|
||||
// if !ok {
|
||||
// fmt.Printf("\nERROR 启动进程代理失败,检查是否以管理员身份运行\n")
|
||||
// fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
// select {}
|
||||
// }
|
||||
// Sunny.ProcessAddName("WeChatAppEx.exe")
|
||||
} else {
|
||||
err = proxy.EnableProxy(proxy.ProxySettings{
|
||||
Device: args.Device,
|
||||
Hostname: "127.0.0.1",
|
||||
Port: strconv.Itoa(args.Port),
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("\nERROR 设置代理失败 %v\n", err.Error())
|
||||
fmt.Printf("按 Ctrl+C 退出...\n")
|
||||
select {}
|
||||
}
|
||||
}
|
||||
color.Green(fmt.Sprintf("\n\n服务已正确启动,请打开需要下载的视频号页面进行下载"))
|
||||
fmt.Println("\n\n服务正在运行,按 Ctrl+C 退出...")
|
||||
select {}
|
||||
}
|
||||
|
||||
type UninstallCertificateCommandArgs struct {
|
||||
}
|
||||
|
||||
func uninstall_certificate_command(args UninstallCertificateCommandArgs) {
|
||||
settings := proxy.ProxySettings{}
|
||||
if err := proxy.DisableProxy(settings); err != nil {
|
||||
fmt.Printf("\nERROR 取消代理失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
if err := certificate.UninstallCertificate(RootCertificateName); err != nil {
|
||||
fmt.Printf("\nERROR 删除根证书失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
color.Green(fmt.Sprintf("\n\n删除根证书 '%v' 成功\n", RootCertificateName))
|
||||
}
|
||||
|
||||
type DownloadCommandArgs struct {
|
||||
URL string
|
||||
Filename string
|
||||
DecryptKey int
|
||||
}
|
||||
|
||||
func download_command(args DownloadCommandArgs) {
|
||||
url := args.URL
|
||||
homedir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]获取下载路径失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
tmp_filename := "tmp_wx_" + strconv.Itoa(int(time.Now().Unix()))
|
||||
tmp_dest_filepath := filepath.Join(homedir, "Downloads", tmp_filename)
|
||||
dest_filepath := filepath.Join(homedir, "Downloads", args.Filename)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]下载失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
file, err := os.Create(tmp_dest_filepath)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]下载文件失败 %v\n", err.Error())
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
content_length := resp.Header.Get("Content-Length")
|
||||
total_size := int64(-1)
|
||||
if content_length != "" {
|
||||
total_size, _ = strconv.ParseInt(content_length, 10, 64)
|
||||
}
|
||||
buf := make([]byte, 32*1024) // 32KB buffer
|
||||
var downloaded int64 = 0
|
||||
for {
|
||||
n, err := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
_, werr := file.Write(buf[:n])
|
||||
if werr != nil {
|
||||
fmt.Printf("[ERROR]写入文件失败 %v\n", werr.Error())
|
||||
return
|
||||
}
|
||||
downloaded += int64(n)
|
||||
if total_size > 0 {
|
||||
percent := float64(downloaded) / float64(total_size) * 100
|
||||
fmt.Printf("\r\033[K已下载: %d/%d 字节 (%.2f%%)", downloaded, total_size, percent)
|
||||
} else {
|
||||
fmt.Printf("\r\033[K已下载: %d 字节", downloaded)
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]下载文件失败2 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
if args.DecryptKey != 0 {
|
||||
fmt.Printf("开始对文件解密 %s\n", tmp_dest_filepath)
|
||||
length := uint32(131072)
|
||||
enclen_str := resp.Header.Get("X-enclen")
|
||||
if enclen_str != "" {
|
||||
v, err := strconv.ParseUint(enclen_str, 10, 32)
|
||||
if err == nil {
|
||||
length = uint32(v)
|
||||
}
|
||||
}
|
||||
key := uint64(args.DecryptKey)
|
||||
data, err := os.ReadFile(tmp_dest_filepath)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]读取已下载的文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
decrypt.DecryptData(data, length, key)
|
||||
err = os.WriteFile(dest_filepath, data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]写入文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
file.Close()
|
||||
if err := os.Remove(tmp_dest_filepath); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println("[ERROR]临时文件不存在")
|
||||
} else if os.IsPermission(err) {
|
||||
fmt.Println("[ERROR]没有权限删除临时文件")
|
||||
} else {
|
||||
fmt.Printf("[ERROR]临时文件删除失败 %v\n", err.Error())
|
||||
}
|
||||
}
|
||||
fmt.Printf("解密完成,文件路径为 %s\n", dest_filepath)
|
||||
return
|
||||
}
|
||||
fmt.Printf("下载完成,文件路径为 %s\n", dest_filepath)
|
||||
}
|
||||
|
||||
type DecryptCOmmandArgs struct {
|
||||
Filepath string
|
||||
DecryptKey int
|
||||
}
|
||||
|
||||
func decrypt_command(args DecryptCOmmandArgs) {
|
||||
fmt.Printf("开始对文件解密 %s\n", args.Filepath)
|
||||
length := uint32(131072)
|
||||
key := uint64(args.DecryptKey)
|
||||
data, err := os.ReadFile(args.Filepath)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]读取已下载的文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
decrypt.DecryptData(data, length, key)
|
||||
err = os.WriteFile(args.Filepath, data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]写入文件失败 %v\n", err.Error())
|
||||
return
|
||||
}
|
||||
fmt.Printf("解密完成 %s\n", args.Filepath)
|
||||
}
|
||||
+156
-61
@@ -1,6 +1,7 @@
|
||||
package download
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var file_mutex sync.Mutex
|
||||
|
||||
type FileDownloadProgress struct {
|
||||
Current int64
|
||||
Total int64
|
||||
@@ -96,6 +99,49 @@ func progress_bar(percentage float64, width int) string {
|
||||
return bar
|
||||
}
|
||||
|
||||
func calculate_chunks(total_size, preferred_chunk_size int64) []struct{ start, end int64 } {
|
||||
const (
|
||||
minChunkSize = 1 * 1024 * 1024 // 1MB最小分块
|
||||
maxChunks = 8 // 最大分块数
|
||||
minChunks = 2 // 最小分块数
|
||||
)
|
||||
|
||||
// 计算初始分块数
|
||||
num_chunks := total_size / preferred_chunk_size
|
||||
if num_chunks < minChunks {
|
||||
num_chunks = minChunks
|
||||
} else if num_chunks > maxChunks {
|
||||
num_chunks = maxChunks
|
||||
}
|
||||
|
||||
// 重新计算分块大小
|
||||
chunk_size := total_size / num_chunks
|
||||
|
||||
// 确保分块不小于最小值
|
||||
if chunk_size < minChunkSize {
|
||||
chunk_size = minChunkSize
|
||||
num_chunks = total_size / chunk_size
|
||||
if num_chunks == 0 {
|
||||
num_chunks = 1
|
||||
}
|
||||
}
|
||||
|
||||
var chunks []struct{ start, end int64 }
|
||||
for i := int64(0); i < num_chunks; i++ {
|
||||
start := i * chunk_size
|
||||
end := start + chunk_size - 1
|
||||
|
||||
// 最后一个分块包含剩余所有数据
|
||||
if i == num_chunks-1 {
|
||||
end = total_size - 1
|
||||
}
|
||||
|
||||
chunks = append(chunks, struct{ start, end int64 }{start, end})
|
||||
}
|
||||
|
||||
return chunks
|
||||
}
|
||||
|
||||
// 带进度显示的文件分块下载
|
||||
func download_part_with_progress(url string, file *os.File, start, end int64, thread_idx int, progress_chan chan<- FileDownloadProgress) error {
|
||||
client := &http.Client{Timeout: 0} // 无超时限制
|
||||
@@ -121,12 +167,6 @@ func download_part_with_progress(url string, file *os.File, start, end int64, th
|
||||
return fmt.Errorf("服务器返回错误状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
// 定位到文件的指定位置
|
||||
// _, err = file.Seek(start, io.SeekStart)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// 创建带进度统计的Reader
|
||||
total_size := end - start + 1
|
||||
progress_reader := &ProgressReader{
|
||||
@@ -136,12 +176,23 @@ func download_part_with_progress(url string, file *os.File, start, end int64, th
|
||||
Channel: progress_chan,
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
if _, err := io.Copy(buf, progress_reader); err != nil {
|
||||
return err
|
||||
}
|
||||
// 将下载的数据写入文件的指定位置
|
||||
_, err = io.Copy(file, progress_reader)
|
||||
|
||||
// 同步写入文件
|
||||
file_mutex.Lock()
|
||||
defer file_mutex.Unlock()
|
||||
// 定位到文件的指定位置
|
||||
_, err = file.Seek(start, io.SeekStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := file.Write(buf.Bytes()); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -191,81 +242,134 @@ func (pr *ProgressReader) Read(p []byte) (int, error) {
|
||||
return n, err
|
||||
}
|
||||
|
||||
func download(url string, threads int, tmp_dest_filepath string) {
|
||||
type PartialFileDownloadProgress struct {
|
||||
DownloadedSize int64
|
||||
TotalSize int64
|
||||
Percent float64
|
||||
}
|
||||
|
||||
func SingleThreadingDownload(url string, dest_filepath string, on_progress func(progress *PartialFileDownloadProgress)) error {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return fmt.Errorf("下载失败 %v", err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
file, err := os.Create(dest_filepath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建文件失败 %v", err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
content_length := resp.Header.Get("Content-Length")
|
||||
total_size := int64(-1)
|
||||
if content_length != "" {
|
||||
total_size, _ = strconv.ParseInt(content_length, 10, 64)
|
||||
}
|
||||
buf := make([]byte, 32*1024) // 32KB buffer
|
||||
var downloaded int64 = 0
|
||||
for {
|
||||
n, err := resp.Body.Read(buf)
|
||||
if n > 0 {
|
||||
_, werr := file.Write(buf[:n])
|
||||
if werr != nil {
|
||||
return fmt.Errorf("写入文件失败 %v", werr.Error())
|
||||
}
|
||||
downloaded += int64(n)
|
||||
if total_size > 0 {
|
||||
percent := float64(downloaded) / float64(total_size) * 100
|
||||
on_progress(&PartialFileDownloadProgress{
|
||||
DownloadedSize: downloaded,
|
||||
TotalSize: total_size,
|
||||
Percent: percent,
|
||||
})
|
||||
// fmt.Printf("\r\033[K已下载: %d/%d 字节 (%.2f%%)", downloaded, total_size, percent)
|
||||
} else {
|
||||
on_progress(&PartialFileDownloadProgress{
|
||||
DownloadedSize: downloaded,
|
||||
TotalSize: 0,
|
||||
Percent: 0,
|
||||
})
|
||||
// fmt.Printf("\r\033[K已下载: %d 字节", downloaded)
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("读取文件流失败 %v", err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func MultiThreadingDownload(url string, threads int, dest_filepath string, tmp_dest_filepath string) error {
|
||||
tr := &http.Transport{
|
||||
TLSNextProto: make(map[string]func(authority string, c *tls.Conn) http.RoundTripper),
|
||||
}
|
||||
client := &http.Client{Transport: tr, Timeout: 30 * time.Second}
|
||||
|
||||
// 发送HEAD请求获取文件信息
|
||||
resp, err := client.Head(url)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]获取文件信息失败 %v\n", err.Error())
|
||||
os.Exit(0)
|
||||
return
|
||||
return fmt.Errorf("获取文件信息失败 %v", err.Error())
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
fmt.Print("\033c")
|
||||
|
||||
// 检查是否支持断点续传
|
||||
if resp.Header.Get("Accept-Ranges") != "bytes" {
|
||||
fmt.Printf("[ERROR]服务器不支持断点续传")
|
||||
os.Exit(0)
|
||||
return
|
||||
return fmt.Errorf("服务器不支持并发下载")
|
||||
}
|
||||
|
||||
content_length := resp.Header.Get("Content-Length")
|
||||
if content_length == "" {
|
||||
fmt.Printf("[ERROR]无法获取文件大小")
|
||||
os.Exit(0)
|
||||
return
|
||||
return fmt.Errorf("无法获取总文件大小,服务器不支持并发下载")
|
||||
}
|
||||
|
||||
file_size, err := strconv.ParseInt(content_length, 10, 64)
|
||||
if err != nil {
|
||||
fmt.Printf("[ERROR]解析文件大小失败: %v", err)
|
||||
return
|
||||
return fmt.Errorf("解析文件大小失败: %v", err)
|
||||
}
|
||||
|
||||
fmt.Printf("文件大小: %.2f MB\n", float64(file_size)/1024/1024)
|
||||
|
||||
start_time := time.Now()
|
||||
// start_time := time.Now()
|
||||
var wg sync.WaitGroup
|
||||
errors := make(chan error, threads)
|
||||
|
||||
// 计算每个分块的大小
|
||||
part_size := file_size / int64(threads)
|
||||
// remainder := file_size % int64(threads)
|
||||
|
||||
chunks := calculate_chunks(file_size, part_size)
|
||||
// 创建进度通道,每个线程一个
|
||||
progress_chans := make([]chan FileDownloadProgress, threads)
|
||||
progress_chans := make([]chan FileDownloadProgress, len(chunks))
|
||||
for i := range progress_chans {
|
||||
progress_chans[i] = make(chan FileDownloadProgress, 10)
|
||||
}
|
||||
|
||||
// 计算每个分块的大小
|
||||
part_size := file_size / int64(threads)
|
||||
remainder := file_size % int64(threads)
|
||||
|
||||
// 启动进度显示器
|
||||
stop_progress := make(chan bool)
|
||||
go display_progress(progress_chans, stop_progress)
|
||||
|
||||
file, err := os.Create(dest_filepath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建文件失败 %v\n", err)
|
||||
}
|
||||
defer file.Close()
|
||||
if err := file.Truncate(file_size); err != nil {
|
||||
return fmt.Errorf("设置文件大小失败: %v", err)
|
||||
}
|
||||
|
||||
// fmt.Println("the chunk size is", len(chunks))
|
||||
// 启动并发下载
|
||||
for i := 0; i < threads; i++ {
|
||||
for i, chunk := range chunks {
|
||||
wg.Add(1)
|
||||
|
||||
// 计算当前分块的起始和结束位置
|
||||
start := int64(i) * part_size
|
||||
end := start + part_size - 1
|
||||
|
||||
// 最后一个线程处理剩余的部分
|
||||
if i == threads-1 {
|
||||
end += remainder
|
||||
}
|
||||
// fmt.Println(i, chunk)
|
||||
go func(thread_idx int, start, end int64) {
|
||||
defer wg.Done()
|
||||
file, err := os.Create(tmp_dest_filepath + "_" + strconv.Itoa(thread_idx))
|
||||
if err != nil {
|
||||
errors <- fmt.Errorf("创建文件 %d 失败: %v", thread_idx+1, err)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
// file, err := os.Create(tmp_dest_filepath + "_" + strconv.Itoa(thread_idx))
|
||||
// if err != nil {
|
||||
// errors <- fmt.Errorf("创建文件 %d 失败: %v", thread_idx+1, err)
|
||||
// return
|
||||
// }
|
||||
// defer file.Close()
|
||||
if err := download_part_with_progress(
|
||||
url,
|
||||
file,
|
||||
@@ -276,7 +380,7 @@ func download(url string, threads int, tmp_dest_filepath string) {
|
||||
); err != nil {
|
||||
errors <- fmt.Errorf("线程 %d 下载失败: %v", thread_idx+1, err)
|
||||
}
|
||||
}(i, start, end)
|
||||
}(i, chunk.start, chunk.end)
|
||||
}
|
||||
// 等待所有下载完成
|
||||
wg.Wait()
|
||||
@@ -285,19 +389,10 @@ func download(url string, threads int, tmp_dest_filepath string) {
|
||||
|
||||
// 检查错误
|
||||
if len(errors) > 0 {
|
||||
for err := range errors {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println("下载失败")
|
||||
return
|
||||
// for err := range errors {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
return fmt.Errorf("下载失败,共%v个错误", len(errors))
|
||||
}
|
||||
|
||||
elapsed := time.Since(start_time)
|
||||
speed := float64(file_size) / elapsed.Seconds() / 1024 / 1024
|
||||
|
||||
fmt.Printf("\n下载完成!\n")
|
||||
// fmt.Printf("文件名: %s\n", tmp_filename)
|
||||
fmt.Printf("文件大小: %.2f MB\n", float64(file_size)/1024/1024)
|
||||
fmt.Printf("耗时: %.2f 秒\n", elapsed.Seconds())
|
||||
fmt.Printf("平均速度: %.2f MB/s\n", speed)
|
||||
return nil
|
||||
}
|
||||
+20
-2
@@ -12,10 +12,28 @@ type HardwarePort struct {
|
||||
Interface string
|
||||
}
|
||||
|
||||
func merge_default_settings(p ProxySettings) ProxySettings {
|
||||
if p.Device == "" {
|
||||
p.Device = "Wi-Fi" // 默认使用 Wi-Fi 设备
|
||||
device, err := get_network_interfaces()
|
||||
if err == nil {
|
||||
p.Device = device.Port
|
||||
}
|
||||
}
|
||||
if p.Hostname == "" {
|
||||
p.Hostname = "127.0.0.1"
|
||||
}
|
||||
if p.Port == "" {
|
||||
p.Port = "2023"
|
||||
}
|
||||
return p
|
||||
|
||||
}
|
||||
|
||||
func EnableProxy(arg ProxySettings) error {
|
||||
return enableProxy(arg)
|
||||
return enable_proxy(arg)
|
||||
}
|
||||
|
||||
func DisableProxy(arg ProxySettings) error {
|
||||
return disableProxy(arg)
|
||||
return disable_proxy(arg)
|
||||
}
|
||||
@@ -9,26 +9,8 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func mergeDefaultSettings(p ProxySettings) ProxySettings {
|
||||
if p.Device == "" {
|
||||
p.Device = "Wi-Fi" // 默认使用 Wi-Fi 设备
|
||||
device, err := getNetworkInterfaces()
|
||||
if err == nil {
|
||||
p.Device = device.Port
|
||||
}
|
||||
}
|
||||
if p.Hostname == "" {
|
||||
p.Hostname = "127.0.0.1"
|
||||
}
|
||||
if p.Port == "" {
|
||||
p.Port = "2023"
|
||||
}
|
||||
return p
|
||||
|
||||
}
|
||||
|
||||
func enableProxy(args ProxySettings) error {
|
||||
args = mergeDefaultSettings(args)
|
||||
func enable_proxy(args ProxySettings) error {
|
||||
args = merge_default_settings(args)
|
||||
cmd1 := exec.Command("networksetup", "-setwebproxy", args.Device, args.Hostname, args.Port)
|
||||
_, err1 := cmd1.Output()
|
||||
if err1 != nil {
|
||||
@@ -42,8 +24,8 @@ func enableProxy(args ProxySettings) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func disableProxy(args ProxySettings) error {
|
||||
args = mergeDefaultSettings(args)
|
||||
func disable_proxy(args ProxySettings) error {
|
||||
args = merge_default_settings(args)
|
||||
cmd1 := exec.Command("networksetup", "-setwebproxystate", args.Device, "off")
|
||||
_, err1 := cmd1.Output()
|
||||
if err1 != nil {
|
||||
@@ -57,7 +39,7 @@ func disableProxy(args ProxySettings) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNetworkInterfaces() (*HardwarePort, error) {
|
||||
func get_network_interfaces() (*HardwarePort, error) {
|
||||
// 获取所有硬件端口信息
|
||||
cmd := exec.Command("networksetup", "-listallhardwareports")
|
||||
output, err := cmd.Output()
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -11,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
// EnableProxyInLinux sets GNOME / Deepin proxy with correct user context
|
||||
func enableProxy(ps ProxySettings) error {
|
||||
func enable_proxy(ps ProxySettings) error {
|
||||
if ps.Hostname == "" {
|
||||
ps.Hostname = "127.0.0.1"
|
||||
}
|
||||
@@ -76,7 +77,7 @@ func enableProxy(ps ProxySettings) error {
|
||||
}
|
||||
|
||||
// DisableProxyInLinux 关闭 GNOME / Deepin 的系统代理
|
||||
func disableProxy(arg ProxySettings) error {
|
||||
func disable_proxy(arg ProxySettings) error {
|
||||
loginUserBytes, err := exec.Command("logname").Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取登录用户失败(logname): %v", err)
|
||||
@@ -118,3 +119,7 @@ func disableProxy(arg ProxySettings) error {
|
||||
fmt.Println("✅ 已关闭系统代理(Linux)")
|
||||
return nil
|
||||
}
|
||||
|
||||
func get_network_interfaces() (*HardwarePort, error) {
|
||||
return nil, errors.New("not support")
|
||||
}
|
||||
@@ -2,12 +2,48 @@
|
||||
|
||||
package proxy
|
||||
|
||||
import "errors"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func enableProxy(ps ProxySettings) error {
|
||||
return errors.New("Windows 平台暂不支持")
|
||||
func enable_proxy(args ProxySettings) error {
|
||||
args = merge_default_settings(args)
|
||||
// netsh winhttp set proxy 127.0.0.1:8080
|
||||
path := `HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings`
|
||||
proxy_server_url := fmt.Sprintf("%v:%v", args.Hostname, args.Port)
|
||||
// # 启用代理
|
||||
// Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name ProxyEnable -Value 1
|
||||
// Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name ProxyServer -Value "127.0.0.1:8080"
|
||||
// cmd1 := exec.Command("netsh", "winhttp", "set", "proxy", fmt.Sprintf("%v:%v", args.Hostname, args.Port))
|
||||
cmd1 := exec.Command("Set-ItemProperty", "-Path", path, "-Name", "ProxyEnable", "-Value", "1")
|
||||
// fmt.Sprintf("%v:%v", args.Hostname, args.Port)
|
||||
_, err := cmd1.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("设置 HTTP 代理失败,%v", err.Error())
|
||||
}
|
||||
cmd2 := exec.Command("Set-ItemProperty", "-Path", path, "-Name", "ProxyServer", "-Value", proxy_server_url)
|
||||
_, err = cmd2.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("设置 HTTP 代理失败,%v", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func disableProxy(ps ProxySettings) error {
|
||||
return errors.New("Windows 平台暂不支持")
|
||||
func disable_proxy(args ProxySettings) error {
|
||||
path := `HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings`
|
||||
// # 禁用代理
|
||||
// Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings" -Name ProxyEnable -Value 0
|
||||
cmd1 := exec.Command("Set-ItemProperty", "-Path", path, "-Name", "ProxyEnable", "-Value", "0")
|
||||
// fmt.Sprintf("%v:%v", args.Hostname, args.Port)
|
||||
_, err := cmd1.Output()
|
||||
if err != nil {
|
||||
return fmt.Errorf("设置 HTTP 代理失败,%v", err.Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func get_network_interfaces() (*HardwarePort, error) {
|
||||
return nil, errors.New("not support")
|
||||
}
|
||||
Reference in new issue
Block a user