mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-12 14:14:55 +08:00
Compare commits
2 Commits
6086bd7086
...
a247c708f6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a247c708f6 | ||
|
|
85781a150a |
18
core/app.go
18
core/app.go
@@ -166,30 +166,28 @@ func (a *App) installCert() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) OpenSystemProxy() bool {
|
func (a *App) OpenSystemProxy() error {
|
||||||
if a.IsProxy {
|
if a.IsProxy {
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
err := systemOnce.setProxy()
|
err := systemOnce.setProxy()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
a.IsProxy = true
|
a.IsProxy = true
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
DialogErr("设置失败:" + err.Error())
|
return err
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) UnsetSystemProxy() bool {
|
func (a *App) UnsetSystemProxy() error {
|
||||||
if !a.IsProxy {
|
if !a.IsProxy {
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
err := systemOnce.unsetProxy()
|
err := systemOnce.unsetProxy()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
a.IsProxy = false
|
a.IsProxy = false
|
||||||
return true
|
return nil
|
||||||
}
|
}
|
||||||
DialogErr("设置失败:" + err.Error())
|
return err
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) isInstall() bool {
|
func (a *App) isInstall() bool {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProgressCallback func(totalDownloaded float64)
|
type ProgressCallback func(totalDownloaded float64, totalSize float64)
|
||||||
|
|
||||||
type DownloadTask struct {
|
type DownloadTask struct {
|
||||||
taskID int
|
taskID int
|
||||||
@@ -53,16 +53,15 @@ func (fd *FileDownloader) buildClient() *http.Client {
|
|||||||
if fd.ProxyUrl != nil {
|
if fd.ProxyUrl != nil {
|
||||||
transport.Proxy = http.ProxyURL(fd.ProxyUrl)
|
transport.Proxy = http.ProxyURL(fd.ProxyUrl)
|
||||||
}
|
}
|
||||||
// Cookie handle
|
|
||||||
return &http.Client{
|
return &http.Client{
|
||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FileDownloader) setHeaders(request *http.Request) {
|
func (fd *FileDownloader) setHeaders(request *http.Request) {
|
||||||
for key, values := range fd.Headers {
|
for key, value := range fd.Headers {
|
||||||
if strings.Contains(globalConfig.UseHeaders, key) {
|
if strings.Contains(globalConfig.UseHeaders, key) {
|
||||||
request.Header.Set(key, values)
|
request.Header.Set(key, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,50 +84,42 @@ func (fd *FileDownloader) init() error {
|
|||||||
|
|
||||||
request, err := http.NewRequest("HEAD", fd.Url, nil)
|
request, err := http.NewRequest("HEAD", fd.Url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("create request failed")
|
return fmt.Errorf("create HEAD request failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := fd.Headers["User-Agent"]; !ok {
|
if _, ok := fd.Headers["User-Agent"]; !ok {
|
||||||
fd.Headers["User-Agent"] = globalConfig.UserAgent
|
fd.Headers["User-Agent"] = globalConfig.UserAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := fd.Headers["Referer"]; !ok {
|
if _, ok := fd.Headers["Referer"]; !ok {
|
||||||
fd.Headers["Referer"] = fd.Referer
|
fd.Headers["Referer"] = fd.Referer
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.setHeaders(request)
|
fd.setHeaders(request)
|
||||||
|
|
||||||
resp, err := fd.buildClient().Do(request)
|
resp, err := fd.buildClient().Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("request failed" + err.Error())
|
return fmt.Errorf("HEAD request failed: %w", err)
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
fd.TotalSize = resp.ContentLength
|
fd.TotalSize = resp.ContentLength
|
||||||
|
|
||||||
if fd.TotalSize <= 0 {
|
if fd.TotalSize <= 0 {
|
||||||
return fmt.Errorf("request init failed: size 0")
|
return fmt.Errorf("invalid file size")
|
||||||
}
|
}
|
||||||
|
if resp.Header.Get("Accept-Ranges") == "bytes" && fd.TotalSize > 10*1024*1024 {
|
||||||
if resp.Header.Get("Accept-Ranges") == "bytes" && fd.TotalSize > 10485760 {
|
|
||||||
fd.IsMultiPart = true
|
fd.IsMultiPart = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.FileName = filepath.Clean(fd.FileName)
|
|
||||||
|
|
||||||
dir := filepath.Dir(fd.FileName)
|
dir := filepath.Dir(fd.FileName)
|
||||||
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.File, err = os.OpenFile(fd.FileName, os.O_RDWR|os.O_CREATE, 0644)
|
fd.File, err = os.OpenFile(fd.FileName, os.O_RDWR|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("文件初始化失败: %w", err)
|
return fmt.Errorf("file open failed: %w", err)
|
||||||
}
|
}
|
||||||
|
if err := fd.File.Truncate(fd.TotalSize); err != nil {
|
||||||
if err = fd.File.Truncate(fd.TotalSize); err != nil {
|
|
||||||
fd.File.Close()
|
fd.File.Close()
|
||||||
return fmt.Errorf("文件大小设置失败: %w", err)
|
return fmt.Errorf("file truncate failed: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -139,97 +130,100 @@ func (fd *FileDownloader) createDownloadTasks() {
|
|||||||
fd.totalTasks = int(fd.TotalSize)
|
fd.totalTasks = int(fd.TotalSize)
|
||||||
}
|
}
|
||||||
eachSize := fd.TotalSize / int64(fd.totalTasks)
|
eachSize := fd.TotalSize / int64(fd.totalTasks)
|
||||||
|
|
||||||
for i := 0; i < fd.totalTasks; i++ {
|
for i := 0; i < fd.totalTasks; i++ {
|
||||||
|
start := eachSize * int64(i)
|
||||||
|
end := eachSize*int64(i+1) - 1
|
||||||
|
if i == fd.totalTasks-1 {
|
||||||
|
end = fd.TotalSize - 1
|
||||||
|
}
|
||||||
fd.DownloadTaskList = append(fd.DownloadTaskList, &DownloadTask{
|
fd.DownloadTaskList = append(fd.DownloadTaskList, &DownloadTask{
|
||||||
taskID: i,
|
taskID: i,
|
||||||
rangeStart: eachSize * int64(i),
|
rangeStart: start,
|
||||||
rangeEnd: eachSize*int64(i+1) - 1,
|
rangeEnd: end,
|
||||||
downloadedSize: 0,
|
|
||||||
isCompleted: false,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fd.DownloadTaskList[len(fd.DownloadTaskList)-1].rangeEnd = fd.TotalSize - 1
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
fd.DownloadTaskList = append(fd.DownloadTaskList, &DownloadTask{
|
fd.DownloadTaskList = append(fd.DownloadTaskList, &DownloadTask{taskID: 0})
|
||||||
taskID: 0,
|
|
||||||
rangeStart: 0,
|
|
||||||
rangeEnd: 0,
|
|
||||||
downloadedSize: 0,
|
|
||||||
isCompleted: false,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FileDownloader) startDownload() {
|
func (fd *FileDownloader) startDownload() {
|
||||||
waitGroup := &sync.WaitGroup{}
|
wg := &sync.WaitGroup{}
|
||||||
progressChan := make(chan int64)
|
progressChan := make(chan int64)
|
||||||
|
|
||||||
for _, task := range fd.DownloadTaskList {
|
for _, task := range fd.DownloadTaskList {
|
||||||
go fd.startDownloadTask(waitGroup, progressChan, task)
|
wg.Add(1)
|
||||||
waitGroup.Add(1)
|
go fd.startDownloadTask(wg, progressChan, task)
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
waitGroup.Wait()
|
wg.Wait()
|
||||||
close(progressChan)
|
close(progressChan)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if fd.progressCallback != nil {
|
if fd.progressCallback != nil {
|
||||||
totalDownloaded := int64(0)
|
totalDownloaded := int64(0)
|
||||||
for progress := range progressChan {
|
for p := range progressChan {
|
||||||
totalDownloaded += progress
|
totalDownloaded += p
|
||||||
fd.progressCallback(float64(totalDownloaded) * 100 / float64(fd.TotalSize))
|
fd.progressCallback(float64(totalDownloaded), float64(fd.TotalSize))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FileDownloader) startDownloadTask(waitGroup *sync.WaitGroup, progressChan chan int64, task *DownloadTask) {
|
func (fd *FileDownloader) startDownloadTask(wg *sync.WaitGroup, progressChan chan int64, task *DownloadTask) {
|
||||||
defer waitGroup.Done()
|
defer wg.Done()
|
||||||
request, err := http.NewRequest("GET", fd.Url, nil)
|
request, err := http.NewRequest("GET", fd.Url, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
globalLogger.Error().Stack().Err(err).Msgf("任务%d创建请求出错", task.taskID)
|
globalLogger.Error().Stack().Err(err).Msgf("任务%d创建请求出错", task.taskID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fd.setHeaders(request)
|
fd.setHeaders(request)
|
||||||
|
|
||||||
if fd.IsMultiPart {
|
if fd.IsMultiPart {
|
||||||
request.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", task.rangeStart, task.rangeEnd))
|
rangeHeader := fmt.Sprintf("bytes=%d-%d", task.rangeStart, task.rangeEnd)
|
||||||
|
request.Header.Set("Range", rangeHeader)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := fd.buildClient().Do(request)
|
client := fd.buildClient()
|
||||||
|
resp, err := client.Do(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("任务%d发送下载请求出错!%s", task.taskID, err)
|
log.Printf("任务%d发送下载请求出错!%s", task.taskID, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
buf := make([]byte, 8192)
|
buf := make([]byte, 8192)
|
||||||
for {
|
for {
|
||||||
n, err := resp.Body.Read(buf)
|
n, err := resp.Body.Read(buf)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
_, err := fd.File.WriteAt(buf[:n], task.rangeStart+task.downloadedSize)
|
remain := task.rangeEnd - (task.rangeStart + task.downloadedSize) + 1
|
||||||
if err != nil {
|
n64 := int64(n)
|
||||||
log.Printf("任务%d写入文件时出现错误!位置:%d, err: %s\n", task.taskID, task.rangeStart+task.downloadedSize, err)
|
if n64 > remain {
|
||||||
|
n = int(remain)
|
||||||
|
}
|
||||||
|
_, writeErr := fd.File.WriteAt(buf[:n], task.rangeStart+task.downloadedSize)
|
||||||
|
if writeErr != nil {
|
||||||
|
log.Printf("任务%d写入文件时出现错误!位置:%d, err: %s\n", task.taskID, task.rangeStart+task.downloadedSize, writeErr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
downSize := int64(n)
|
task.downloadedSize += n64
|
||||||
task.downloadedSize += downSize
|
progressChan <- n64
|
||||||
progressChan <- downSize
|
|
||||||
|
if task.rangeStart+task.downloadedSize-1 >= task.rangeEnd {
|
||||||
|
task.isCompleted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == io.EOF {
|
if err == io.EOF {
|
||||||
task.isCompleted = true
|
task.isCompleted = true
|
||||||
break
|
|
||||||
}
|
}
|
||||||
log.Printf("任务%d读取响应错误!%s", task.taskID, err)
|
break
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fd *FileDownloader) Start() error {
|
func (fd *FileDownloader) Start() error {
|
||||||
err := fd.init()
|
if err := fd.init(); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fd.createDownloadTasks()
|
fd.createDownloadTasks()
|
||||||
|
|||||||
168
core/http.go
168
core/http.go
@@ -10,11 +10,15 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
sysRuntime "runtime"
|
sysRuntime "runtime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type respData map[string]interface{}
|
||||||
|
|
||||||
type ResponseData struct {
|
type ResponseData struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
@@ -118,20 +122,54 @@ func (h *HttpServer) writeJson(w http.ResponseWriter, data ResponseData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) error(w http.ResponseWriter, args ...interface{}) {
|
||||||
|
message := "ok"
|
||||||
|
var data interface{}
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
message = args[0].(string)
|
||||||
|
}
|
||||||
|
if len(args) > 1 {
|
||||||
|
data = args[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
h.writeJson(w, ResponseData{
|
||||||
|
Code: 0,
|
||||||
|
Message: message,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) success(w http.ResponseWriter, args ...interface{}) {
|
||||||
|
message := "ok"
|
||||||
|
var data interface{}
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
data = args[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) > 1 {
|
||||||
|
message = args[1].(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
h.writeJson(w, ResponseData{
|
||||||
|
Code: 1,
|
||||||
|
Message: message,
|
||||||
|
Data: data,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func (h *HttpServer) openDirectoryDialog(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) openDirectoryDialog(w http.ResponseWriter, r *http.Request) {
|
||||||
folder, err := runtime.OpenDirectoryDialog(appOnce.ctx, runtime.OpenDialogOptions{
|
folder, err := runtime.OpenDirectoryDialog(appOnce.ctx, runtime.OpenDialogOptions{
|
||||||
DefaultDirectory: "",
|
DefaultDirectory: "",
|
||||||
Title: "Select a folder",
|
Title: "Select a folder",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, respData{
|
||||||
Code: 1,
|
"folder": folder,
|
||||||
Data: map[string]interface{}{
|
|
||||||
"folder": folder,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,14 +184,11 @@ func (h *HttpServer) openFileDialog(w http.ResponseWriter, r *http.Request) {
|
|||||||
Title: "Select a file",
|
Title: "Select a file",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, respData{
|
||||||
Code: 1,
|
"file": filePath,
|
||||||
Data: map[string]interface{}{
|
|
||||||
"file": filePath,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,77 +223,87 @@ func (h *HttpServer) openFolder(w http.ResponseWriter, r *http.Request) {
|
|||||||
cmd = exec.Command("pcmanfm", filePath)
|
cmd = exec.Command("pcmanfm", filePath)
|
||||||
if err := cmd.Start(); err != nil {
|
if err := cmd.Start(); err != nil {
|
||||||
globalLogger.err(err)
|
globalLogger.err(err)
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: "unsupported platform"})
|
h.error(w, "unsupported platform")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cmd.Start()
|
err = cmd.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
globalLogger.err(err)
|
globalLogger.err(err)
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *HttpServer) setSystemPassword(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var data struct {
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&data)
|
||||||
|
if err != nil {
|
||||||
|
h.error(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
systemOnce.SetPassword(data.Password)
|
||||||
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) openSystemProxy(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) openSystemProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
appOnce.OpenSystemProxy()
|
err := appOnce.OpenSystemProxy()
|
||||||
h.writeJson(w, ResponseData{
|
if err != nil {
|
||||||
Code: 1,
|
h.error(w, err.Error(), respData{
|
||||||
Data: map[string]bool{
|
|
||||||
"isProxy": appOnce.IsProxy,
|
"isProxy": appOnce.IsProxy,
|
||||||
},
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.success(w, respData{
|
||||||
|
"isProxy": appOnce.IsProxy,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) unsetSystemProxy(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) unsetSystemProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
appOnce.UnsetSystemProxy()
|
err := appOnce.UnsetSystemProxy()
|
||||||
h.writeJson(w, ResponseData{
|
if err != nil {
|
||||||
Code: 1,
|
h.error(w, err.Error(), respData{
|
||||||
Data: map[string]bool{
|
|
||||||
"isProxy": appOnce.IsProxy,
|
"isProxy": appOnce.IsProxy,
|
||||||
},
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.success(w, respData{
|
||||||
|
"isProxy": appOnce.IsProxy,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) isProxy(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) isProxy(w http.ResponseWriter, r *http.Request) {
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, respData{
|
||||||
Code: 1,
|
"isProxy": appOnce.IsProxy,
|
||||||
Data: map[string]interface{}{
|
|
||||||
"isProxy": appOnce.IsProxy,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) appInfo(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) appInfo(w http.ResponseWriter, r *http.Request) {
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, appOnce)
|
||||||
Code: 1,
|
|
||||||
Data: appOnce,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) getConfig(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) getConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, globalConfig)
|
||||||
Code: 1,
|
|
||||||
Data: globalConfig,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) setConfig(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) setConfig(w http.ResponseWriter, r *http.Request) {
|
||||||
var data Config
|
var data Config
|
||||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
globalConfig.setConfig(data)
|
globalConfig.setConfig(data)
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) setType(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) setType(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -274,12 +319,12 @@ func (h *HttpServer) setType(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) clear(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) clear(w http.ResponseWriter, r *http.Request) {
|
||||||
resourceOnce.clear()
|
resourceOnce.clear()
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) delete(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) delete(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -290,7 +335,7 @@ func (h *HttpServer) delete(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err == nil && data.Sign != "" {
|
if err == nil && data.Sign != "" {
|
||||||
resourceOnce.delete(data.Sign)
|
resourceOnce.delete(data.Sign)
|
||||||
}
|
}
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) download(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) download(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -299,11 +344,11 @@ func (h *HttpServer) download(w http.ResponseWriter, r *http.Request) {
|
|||||||
DecodeStr string `json:"decodeStr"`
|
DecodeStr string `json:"decodeStr"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resourceOnce.download(data.MediaInfo, data.DecodeStr)
|
resourceOnce.download(data.MediaInfo, data.DecodeStr)
|
||||||
h.writeJson(w, ResponseData{Code: 1})
|
h.success(w)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpServer) wxFileDecode(w http.ResponseWriter, r *http.Request) {
|
func (h *HttpServer) wxFileDecode(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -313,18 +358,35 @@ func (h *HttpServer) wxFileDecode(w http.ResponseWriter, r *http.Request) {
|
|||||||
DecodeStr string `json:"decodeStr"`
|
DecodeStr string `json:"decodeStr"`
|
||||||
}
|
}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
savePath, err := resourceOnce.wxFileDecode(data.MediaInfo, data.Filename, data.DecodeStr)
|
savePath, err := resourceOnce.wxFileDecode(data.MediaInfo, data.Filename, data.DecodeStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.writeJson(w, ResponseData{Code: 0, Message: err.Error()})
|
h.error(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
h.writeJson(w, ResponseData{
|
h.success(w, respData{
|
||||||
Code: 1,
|
"save_path": savePath,
|
||||||
Data: map[string]string{
|
})
|
||||||
"save_path": savePath,
|
}
|
||||||
},
|
|
||||||
|
func (h *HttpServer) batchImport(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var data struct {
|
||||||
|
Content string `json:"content"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
|
h.error(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fileName := filepath.Join(globalConfig.SaveDirectory, "res-downloader-"+GetCurrentDateTimeFormatted()+".txt")
|
||||||
|
// 0644 是文件权限:-rw-r--r--
|
||||||
|
err := os.WriteFile(fileName, []byte(data.Content), 0644)
|
||||||
|
if err != nil {
|
||||||
|
h.error(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
h.success(w, respData{
|
||||||
|
"file_name": fileName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ func HandleApi(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
switch r.URL.Path {
|
switch r.URL.Path {
|
||||||
case "/api/preview":
|
case "/api/preview":
|
||||||
httpServerOnce.preview(w, r)
|
httpServerOnce.preview(w, r)
|
||||||
|
case "/api/set-system-password":
|
||||||
|
httpServerOnce.setSystemPassword(w, r)
|
||||||
case "/api/proxy-open":
|
case "/api/proxy-open":
|
||||||
httpServerOnce.openSystemProxy(w, r)
|
httpServerOnce.openSystemProxy(w, r)
|
||||||
case "/api/proxy-unset":
|
case "/api/proxy-unset":
|
||||||
@@ -54,6 +56,8 @@ func HandleApi(w http.ResponseWriter, r *http.Request) bool {
|
|||||||
httpServerOnce.download(w, r)
|
httpServerOnce.download(w, r)
|
||||||
case "/api/wx-file-decode":
|
case "/api/wx-file-decode":
|
||||||
httpServerOnce.wxFileDecode(w, r)
|
httpServerOnce.wxFileDecode(w, r)
|
||||||
|
case "/api/batch-import":
|
||||||
|
httpServerOnce.batchImport(w, r)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,8 +147,8 @@ func (r *Resource) download(mediaInfo MediaInfo, decodeStr string) {
|
|||||||
headers, _ := r.parseHeaders(mediaInfo)
|
headers, _ := r.parseHeaders(mediaInfo)
|
||||||
|
|
||||||
downloader := NewFileDownloader(rawUrl, mediaInfo.SavePath, globalConfig.TaskNumber, headers)
|
downloader := NewFileDownloader(rawUrl, mediaInfo.SavePath, globalConfig.TaskNumber, headers)
|
||||||
downloader.progressCallback = func(totalDownloaded float64) {
|
downloader.progressCallback = func(totalDownloaded, totalSize float64) {
|
||||||
r.progressEventsEmit(mediaInfo, strconv.Itoa(int(totalDownloaded))+"%", DownloadStatusRunning)
|
r.progressEventsEmit(mediaInfo, strconv.Itoa(int(totalDownloaded*100/totalSize))+"%", DownloadStatusRunning)
|
||||||
}
|
}
|
||||||
err := downloader.Start()
|
err := downloader.Start()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
type SystemSetup struct {
|
type SystemSetup struct {
|
||||||
CertFile string
|
CertFile string
|
||||||
|
Password string
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSystem() *SystemSetup {
|
func initSystem() *SystemSetup {
|
||||||
@@ -33,3 +34,7 @@ func (s *SystemSetup) initCert() ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *SystemSetup) SetPassword(password string) {
|
||||||
|
s.Password = password
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,15 +9,30 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (s *SystemSetup) runCommand(args []string) ([]byte, error) {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return nil, fmt.Errorf("no command provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd *exec.Cmd
|
||||||
|
if s.Password != "" {
|
||||||
|
cmd = exec.Command("sudo", append([]string{"-S"}, args...)...)
|
||||||
|
cmd.Stdin = bytes.NewReader([]byte(s.Password + "\n"))
|
||||||
|
} else {
|
||||||
|
cmd = exec.Command(args[0], args[1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := cmd.CombinedOutput()
|
||||||
|
return output, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *SystemSetup) getNetworkServices() ([]string, error) {
|
func (s *SystemSetup) getNetworkServices() ([]string, error) {
|
||||||
cmd := exec.Command("networksetup", "-listallnetworkservices")
|
output, err := s.runCommand([]string{"networksetup", "-listallnetworkservices"})
|
||||||
output, err := cmd.Output()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to execute command: %v", err)
|
return nil, fmt.Errorf("failed to execute command: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
services := strings.Split(string(output), "\n")
|
services := strings.Split(string(output), "\n")
|
||||||
|
|
||||||
var activeServices []string
|
var activeServices []string
|
||||||
for _, service := range services {
|
for _, service := range services {
|
||||||
service = strings.TrimSpace(service)
|
service = strings.TrimSpace(service)
|
||||||
@@ -25,15 +40,12 @@ func (s *SystemSetup) getNetworkServices() ([]string, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查服务是否活动
|
infoOutput, err := s.runCommand([]string{"networksetup", "-getinfo", service})
|
||||||
infoCmd := exec.Command("networksetup", "-getinfo", service)
|
|
||||||
infoOutput, err := infoCmd.Output()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("failed to get info for service %s: %v\n", service, err)
|
fmt.Printf("failed to get info for service %s: %v\n", service, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果输出中包含 "IP address:",说明服务是活动的
|
|
||||||
if strings.Contains(string(infoOutput), "IP address:") {
|
if strings.Contains(string(infoOutput), "IP address:") {
|
||||||
activeServices = append(activeServices, service)
|
activeServices = append(activeServices, service)
|
||||||
}
|
}
|
||||||
@@ -53,16 +65,19 @@ func (s *SystemSetup) setProxy() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is := false
|
is := false
|
||||||
|
errs := ""
|
||||||
for _, serviceName := range services {
|
for _, serviceName := range services {
|
||||||
if err := exec.Command("networksetup", "-setwebproxy", serviceName, "127.0.0.1", globalConfig.Port).Run(); err != nil {
|
cmds := [][]string{
|
||||||
fmt.Println(err)
|
{"networksetup", "-setwebproxy", serviceName, "127.0.0.1", globalConfig.Port},
|
||||||
} else {
|
{"networksetup", "-setsecurewebproxy", serviceName, "127.0.0.1", globalConfig.Port},
|
||||||
is = true
|
|
||||||
}
|
}
|
||||||
if err := exec.Command("networksetup", "-setsecurewebproxy", serviceName, "127.0.0.1", globalConfig.Port).Run(); err != nil {
|
for _, args := range cmds {
|
||||||
fmt.Println(err)
|
if output, err := s.runCommand(args); err != nil {
|
||||||
} else {
|
errs = errs + "\n output:" + string(output) + "err:" + err.Error()
|
||||||
is = true
|
fmt.Println("setProxy:", output, " err:", err.Error())
|
||||||
|
} else {
|
||||||
|
is = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +85,7 @@ func (s *SystemSetup) setProxy() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("failed to set proxy for any active network service")
|
return fmt.Errorf("failed to set proxy for any active network service, errs: %s", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SystemSetup) unsetProxy() error {
|
func (s *SystemSetup) unsetProxy() error {
|
||||||
@@ -80,16 +95,19 @@ func (s *SystemSetup) unsetProxy() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
is := false
|
is := false
|
||||||
|
errs := ""
|
||||||
for _, serviceName := range services {
|
for _, serviceName := range services {
|
||||||
if err := exec.Command("networksetup", "-setwebproxystate", serviceName, "off").Run(); err != nil {
|
cmds := [][]string{
|
||||||
fmt.Println(err)
|
{"networksetup", "-setwebproxystate", serviceName, "off"},
|
||||||
} else {
|
{"networksetup", "-setsecurewebproxystate", serviceName, "off"},
|
||||||
is = true
|
|
||||||
}
|
}
|
||||||
if err := exec.Command("networksetup", "-setsecurewebproxystate", serviceName, "off").Run(); err != nil {
|
for _, args := range cmds {
|
||||||
fmt.Println(err)
|
if output, err := s.runCommand(args); err != nil {
|
||||||
} else {
|
errs = errs + "\n output:" + string(output) + "err:" + err.Error()
|
||||||
is = true
|
fmt.Println("unsetProxy:", output, " err:", err.Error())
|
||||||
|
} else {
|
||||||
|
is = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +115,7 @@ func (s *SystemSetup) unsetProxy() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("failed to set proxy for any active network service")
|
return fmt.Errorf("failed to unset proxy for any active network service, errs: %s", errs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SystemSetup) installCert() (string, error) {
|
func (s *SystemSetup) installCert() (string, error) {
|
||||||
@@ -112,10 +130,11 @@ func (s *SystemSetup) installCert() (string, error) {
|
|||||||
return string(passwordOutput), err
|
return string(passwordOutput), err
|
||||||
}
|
}
|
||||||
|
|
||||||
password := bytes.TrimSpace(passwordOutput)
|
password := strings.TrimSpace(string(passwordOutput))
|
||||||
cmd := exec.Command("sudo", "-S", "security", "add-trusted-cert", "-d", "-r", "trustRoot", "-k", "/Library/Keychains/System.keychain", s.CertFile)
|
s.SetPassword(password)
|
||||||
|
|
||||||
cmd.Stdin = bytes.NewReader(append(password, '\n'))
|
cmd := exec.Command("sudo", "-S", "security", "add-trusted-cert", "-d", "-r", "trustRoot", "-k", "/Library/Keychains/System.keychain", s.CertFile)
|
||||||
|
cmd.Stdin = bytes.NewReader([]byte(password + "\n"))
|
||||||
output, err := cmd.CombinedOutput()
|
output, err := cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return string(output), err
|
return string(output), err
|
||||||
|
|||||||
1
frontend/components.d.ts
vendored
1
frontend/components.d.ts
vendored
@@ -37,6 +37,7 @@ declare module 'vue' {
|
|||||||
NSpace: typeof import('naive-ui')['NSpace']
|
NSpace: typeof import('naive-ui')['NSpace']
|
||||||
NSwitch: typeof import('naive-ui')['NSwitch']
|
NSwitch: typeof import('naive-ui')['NSwitch']
|
||||||
NTooltip: typeof import('naive-ui')['NTooltip']
|
NTooltip: typeof import('naive-ui')['NTooltip']
|
||||||
|
Password: typeof import('./src/components/Password.vue')['default']
|
||||||
Preview: typeof import('./src/components/Preview.vue')['default']
|
Preview: typeof import('./src/components/Preview.vue')['default']
|
||||||
ResAction: typeof import('./src/components/ResAction.vue')['default']
|
ResAction: typeof import('./src/components/ResAction.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import request from '@/api/request'
|
import request from '@/api/request'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
setSystemPassword(data: object) {
|
||||||
|
return request({
|
||||||
|
url: 'api/set-system-password',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
},
|
||||||
openSystemProxy() {
|
openSystemProxy() {
|
||||||
return request({
|
return request({
|
||||||
url: 'api/proxy-open',
|
url: 'api/proxy-open',
|
||||||
@@ -93,4 +100,11 @@ export default {
|
|||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
batchImport(data: object) {
|
||||||
|
return request({
|
||||||
|
url: 'api/batch-import',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
},
|
||||||
}
|
}
|
||||||
46
frontend/src/components/Password.vue
Normal file
46
frontend/src/components/Password.vue
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<template>
|
||||||
|
<n-modal
|
||||||
|
:show="showModal"
|
||||||
|
:on-update:show="changeShow"
|
||||||
|
style="--wails-draggable:no-drag"
|
||||||
|
preset="dialog"
|
||||||
|
title="管理员授权"
|
||||||
|
content=""
|
||||||
|
:show-icon="false"
|
||||||
|
:mask-closable="false"
|
||||||
|
class="rounded-lg"
|
||||||
|
>
|
||||||
|
<n-form>
|
||||||
|
<div class="text-red-500 text-base">
|
||||||
|
本操作需要管理员授权,仅对本次运行期间有效!
|
||||||
|
</div>
|
||||||
|
<n-form-item path="password" label="">
|
||||||
|
<n-input
|
||||||
|
v-model:value="password"
|
||||||
|
type="password"
|
||||||
|
placeholder="请输入你的电脑密码"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
<template #action>
|
||||||
|
<div class="flex justify-end gap-4">
|
||||||
|
<n-button @click="emits('update:showModal', false)">取消操作</n-button>
|
||||||
|
<n-button type="primary" @click="emits('submit', password)">确认操作</n-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</n-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {ref, computed} from 'vue'
|
||||||
|
import {NModal, NForm, NFormItem, NInput, NButton} from 'naive-ui'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
showModal: Boolean,
|
||||||
|
})
|
||||||
|
const password = ref("")
|
||||||
|
|
||||||
|
const emits = defineEmits(["update:showModal", "submit"])
|
||||||
|
const changeShow = (value: boolean) => emits("update:showModal", value)
|
||||||
|
</script>
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<NButton v-if="row.DecodeKey" type="warning" :tertiary="true" size="small" @click="action('decode')">
|
<NButton v-if="row.DecodeKey" type="warning" :tertiary="true" size="small" @click="action('decode')">
|
||||||
视频解密
|
视频解密
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton v-if="isDebug" type="info" :tertiary="true" size="small" @click="action('json')">
|
<NButton type="info" :tertiary="true" size="small" @click="action('json')">
|
||||||
复制数据
|
复制数据
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton type="error" :tertiary="true" size="small" @click="action('delete')">
|
<NButton type="error" :tertiary="true" size="small" @click="action('delete')">
|
||||||
@@ -22,8 +22,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {inject} from "vue"
|
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
row: any,
|
row: any,
|
||||||
index: number,
|
index: number,
|
||||||
@@ -31,8 +29,6 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emits = defineEmits(["action"])
|
const emits = defineEmits(["action"])
|
||||||
|
|
||||||
const isDebug = inject('isDebug')
|
|
||||||
|
|
||||||
const action = (type: string) => {
|
const action = (type: string) => {
|
||||||
emits('action', props.row, props.index, type)
|
emits('action', props.row, props.index, type)
|
||||||
}
|
}
|
||||||
|
|||||||
6
frontend/src/types/app.d.ts
vendored
6
frontend/src/types/app.d.ts
vendored
@@ -57,4 +57,10 @@ export namespace appType {
|
|||||||
type: string
|
type: string
|
||||||
event: any
|
event: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Res<T = any> {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: T; // T will be the specific type of your data
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col px-5 py-5">
|
<div class="flex flex-col px-5 py-5">
|
||||||
<div class="pb-2 z-40" @click="triggerEvent">
|
<div class="pb-2 z-40">
|
||||||
<NSpace>
|
<NSpace>
|
||||||
<NButton v-if="isProxy" secondary type="primary" @click.stop="close" style="--wails-draggable:no-drag">关闭代理</NButton>
|
<NButton v-if="isProxy" secondary type="primary" @click.stop="close" style="--wails-draggable:no-drag">关闭代理</NButton>
|
||||||
<NButton v-else tertiary type="tertiary" @click.stop="open" style="--wails-draggable:no-drag">开启代理</NButton>
|
<NButton v-else tertiary type="tertiary" @click.stop="open" style="--wails-draggable:no-drag">开启代理</NButton>
|
||||||
<NButton tertiary type="info" @click.stop="batchDown" style="--wails-draggable:no-drag">批量下载</NButton>
|
|
||||||
<NButton tertiary type="error" @click.stop="clear" style="--wails-draggable:no-drag">清空列表</NButton>
|
<NButton tertiary type="error" @click.stop="clear" style="--wails-draggable:no-drag">清空列表</NButton>
|
||||||
<NSelect style="min-width: 100px;--wails-draggable:no-drag" placeholder="拦截类型" v-model:value="resourcesType" multiple clearable :max-tag-count="3" :options="options"></NSelect>
|
<NSelect style="min-width: 100px;--wails-draggable:no-drag" placeholder="拦截类型" v-model:value="resourcesType" multiple clearable :max-tag-count="3" :options="options"></NSelect>
|
||||||
<NButton v-if="isDebug" tertiary type="info" @click.stop="showImport=true" style="--wails-draggable:no-drag">导入数据</NButton>
|
<NButton tertiary type="info" @click.stop="batchDown" style="--wails-draggable:no-drag">批量下载</NButton>
|
||||||
|
<NButton tertiary type="info" @click.stop="batchImport" style="--wails-draggable:no-drag">批量导出</NButton>
|
||||||
|
<NButton tertiary type="info" @click.stop="showImport=true" style="--wails-draggable:no-drag">批量导入</NButton>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
<Preview v-model:showModal="showPreviewRow" :previewRow="previewRow"/>
|
<Preview v-model:showModal="showPreviewRow" :previewRow="previewRow"/>
|
||||||
<ShowLoading :loadingText="loadingText" :isLoading="loading"/>
|
<ShowLoading :loadingText="loadingText" :isLoading="loading"/>
|
||||||
<ImportJson v-model:showModal="showImport" @submit="handleImport"/>
|
<ImportJson v-model:showModal="showImport" @submit="handleImport"/>
|
||||||
|
<Password v-model:showModal="showPassword" @submit="handlePassword"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -47,6 +49,7 @@ import ResAction from "@/components/ResAction.vue"
|
|||||||
import ImportJson from "@/components/ImportJson.vue"
|
import ImportJson from "@/components/ImportJson.vue"
|
||||||
import {useEventStore} from "@/stores/event"
|
import {useEventStore} from "@/stores/event"
|
||||||
import {BrowserOpenURL, ClipboardSetText} from "../../wailsjs/runtime"
|
import {BrowserOpenURL, ClipboardSetText} from "../../wailsjs/runtime"
|
||||||
|
import Password from "@/components/Password.vue"
|
||||||
|
|
||||||
const eventStore = useEventStore()
|
const eventStore = useEventStore()
|
||||||
const isProxy = computed(() => {
|
const isProxy = computed(() => {
|
||||||
@@ -219,12 +222,8 @@ const showPreviewRow = ref(false)
|
|||||||
const previewRow = ref<appType.MediaInfo>()
|
const previewRow = ref<appType.MediaInfo>()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const loadingText = ref("")
|
const loadingText = ref("")
|
||||||
const isDebug = ref(false)
|
|
||||||
const showImport = ref(false)
|
const showImport = ref(false)
|
||||||
let clickCount = 0
|
const showPassword = ref(false)
|
||||||
let clickTimeout: any = null
|
|
||||||
|
|
||||||
provide('isDebug', isDebug);
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const temp = localStorage.getItem("resources-type")
|
const temp = localStorage.getItem("resources-type")
|
||||||
@@ -361,6 +360,35 @@ const batchDown = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const batchImport = ()=>{
|
||||||
|
if (checkedRowKeysValue.value.length <= 0) {
|
||||||
|
window?.$message?.error('请选择需要导出的数据')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!store.globalConfig.SaveDirectory) {
|
||||||
|
window?.$message?.error("请设置保存目录")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadingText.value = "导出中"
|
||||||
|
loading.value = true
|
||||||
|
let jsonData = []
|
||||||
|
for (let i = 0; i < data.value.length; i++) {
|
||||||
|
jsonData.push(encodeURIComponent(JSON.stringify(data.value[i])))
|
||||||
|
}
|
||||||
|
appApi.batchImport({content: jsonData.join("\n")}).then((res: appType.Res) => {
|
||||||
|
loading.value = false
|
||||||
|
if (res.code === 0) {
|
||||||
|
window?.$message?.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window?.$message?.success("导出成功")
|
||||||
|
window?.$message?.info("文件路径:" + res.data?.file_name, {
|
||||||
|
duration: 5000
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const uint8ArrayToBase64 = (bytes: any) => {
|
const uint8ArrayToBase64 = (bytes: any) => {
|
||||||
let binary = '';
|
let binary = '';
|
||||||
const len = bytes.byteLength;
|
const len = bytes.byteLength;
|
||||||
@@ -390,14 +418,14 @@ const download = (row: appType.MediaInfo, index: number) => {
|
|||||||
loading.value = true
|
loading.value = true
|
||||||
downIndex.value = index
|
downIndex.value = index
|
||||||
if (row.DecodeKey) {
|
if (row.DecodeKey) {
|
||||||
appApi.download({...row, decodeStr: uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))}).then((res: any) => {
|
appApi.download({...row, decodeStr: uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))}).then((res: appType.Res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
window?.$message?.error(res.message)
|
window?.$message?.error(res.message)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
appApi.download({...row, decodeStr: ""}).then((res: any) => {
|
appApi.download({...row, decodeStr: ""}).then((res: appType.Res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
window?.$message?.error(res.message)
|
window?.$message?.error(res.message)
|
||||||
@@ -407,13 +435,25 @@ const download = (row: appType.MediaInfo, index: number) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const open = () => {
|
const open = () => {
|
||||||
appApi.openSystemProxy().then((res: any) => {
|
appApi.openSystemProxy().then((res: appType.Res) => {
|
||||||
|
if (res.code === 0 ){
|
||||||
|
if (store.envInfo.platform === "darwin") {
|
||||||
|
showPassword.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
window?.$message?.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
store.updateProxyStatus(res.data)
|
store.updateProxyStatus(res.data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const close = () => {
|
const close = () => {
|
||||||
appApi.unsetSystemProxy().then((res: any) => {
|
appApi.unsetSystemProxy().then((res: appType.Res) => {
|
||||||
|
if (res.code === 0 ){
|
||||||
|
window?.$message?.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
store.updateProxyStatus(res.data)
|
store.updateProxyStatus(res.data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -429,7 +469,7 @@ const decodeWxFile = (row: appType.MediaInfo, index: number) => {
|
|||||||
window?.$message?.error("无法解密")
|
window?.$message?.error("无法解密")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
appApi.openFileDialog().then((res: any) => {
|
appApi.openFileDialog().then((res: appType.Res) => {
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
window?.$message?.error(res.message)
|
window?.$message?.error(res.message)
|
||||||
return
|
return
|
||||||
@@ -441,7 +481,7 @@ const decodeWxFile = (row: appType.MediaInfo, index: number) => {
|
|||||||
...row,
|
...row,
|
||||||
filename: res.data.file,
|
filename: res.data.file,
|
||||||
decodeStr: uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))
|
decodeStr: uint8ArrayToBase64(getDecryptionArray(row.DecodeKey))
|
||||||
}).then((res: any) => {
|
}).then((res: appType.Res) => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
if (res.code === 0) {
|
if (res.code === 0) {
|
||||||
window?.$message?.error(res.message)
|
window?.$message?.error(res.message)
|
||||||
@@ -456,24 +496,6 @@ const decodeWxFile = (row: appType.MediaInfo, index: number) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const triggerEvent = ()=>{
|
|
||||||
if(isDebug.value) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
clickCount++
|
|
||||||
if (clickCount === 5) {
|
|
||||||
// 连续点击5次开启debug
|
|
||||||
isDebug.value = true
|
|
||||||
clickCount = 0
|
|
||||||
} else {
|
|
||||||
clearTimeout(clickTimeout);
|
|
||||||
clickTimeout = setTimeout(() => {
|
|
||||||
clickCount = 0
|
|
||||||
}, 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleImport = (content: string)=>{
|
const handleImport = (content: string)=>{
|
||||||
content.split("\n").forEach((line, index) => {
|
content.split("\n").forEach((line, index) => {
|
||||||
try {
|
try {
|
||||||
@@ -491,4 +513,14 @@ const handleImport = (content: string)=>{
|
|||||||
localStorage.setItem("resources-data", JSON.stringify(data.value))
|
localStorage.setItem("resources-data", JSON.stringify(data.value))
|
||||||
showImport.value = false
|
showImport.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handlePassword = (password: string)=>{
|
||||||
|
appApi.setSystemPassword({password: password}).then((res: appType.Res)=>{
|
||||||
|
if (res.code === 0) {
|
||||||
|
window?.$message?.error(res.message)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
open()
|
||||||
|
})
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"info": {
|
"info": {
|
||||||
"companyName": "res-downloader",
|
"companyName": "res-downloader",
|
||||||
"productName": "res-downloader",
|
"productName": "res-downloader",
|
||||||
"productVersion": "3.0.5",
|
"productVersion": "3.0.6",
|
||||||
"copyright": "Copyright © 2023",
|
"copyright": "Copyright © 2023",
|
||||||
"comments": "This is a high-value high-performance and diverse resource downloader called res-downloader."
|
"comments": "This is a high-value high-performance and diverse resource downloader called res-downloader."
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user