mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-12 06:04:55 +08:00
perf: update doc, core optimize
This commit is contained in:
BIN
build/.DS_Store
vendored
BIN
build/.DS_Store
vendored
Binary file not shown.
@@ -51,8 +51,7 @@ func GetApp(assets embed.FS, wjs string) *App {
|
||||
Version: version,
|
||||
Description: "res-downloader是一款集网络资源嗅探 + 高速下载功能于一体的软件,高颜值、高性能和多样化,提供个人用户下载自己上传到各大平台的网络资源功能!",
|
||||
Copyright: "Copyright © 2023~" + strconv.Itoa(time.Now().Year()),
|
||||
PublicCrt: []byte(`
|
||||
-----BEGIN CERTIFICATE-----
|
||||
PublicCrt: []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL
|
||||
BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ
|
||||
Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu
|
||||
@@ -76,8 +75,7 @@ e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ
|
||||
D8HixYbEDg==
|
||||
-----END CERTIFICATE-----
|
||||
`),
|
||||
PrivateKey: []byte(`
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
PrivateKey: []byte(`-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG
|
||||
/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ
|
||||
H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS
|
||||
|
||||
@@ -46,6 +46,7 @@ func initConfig() *Config {
|
||||
"Host": "127.0.0.1",
|
||||
"Port": "8899",
|
||||
"Theme": "lightTheme",
|
||||
"Locale": "zh",
|
||||
"Quality": 0,
|
||||
"SaveDirectory": "",
|
||||
"FilenameLen": 0,
|
||||
@@ -53,7 +54,7 @@ func initConfig() *Config {
|
||||
"UpstreamProxy": "",
|
||||
"OpenProxy": false,
|
||||
"DownloadProxy": false,
|
||||
"AutoProxy": true,
|
||||
"AutoProxy": false,
|
||||
"WxAction": true,
|
||||
"TaskNumber": __TaskNumber__,
|
||||
"UserAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36",
|
||||
@@ -215,13 +216,15 @@ func (c *Config) getConfig(key string) interface{} {
|
||||
case "UseHeaders":
|
||||
return c.UseHeaders
|
||||
case "MimeMap":
|
||||
mimeMux.RLock()
|
||||
defer mimeMux.RUnlock()
|
||||
return c.MimeMap
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) TypeSuffix(mime string) (string, string) {
|
||||
func (c *Config) typeSuffix(mime string) (string, string) {
|
||||
mimeMux.RLock()
|
||||
defer mimeMux.RUnlock()
|
||||
mime = strings.ToLower(strings.Split(mime, ";")[0])
|
||||
|
||||
@@ -13,30 +13,19 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 定义常量
|
||||
const (
|
||||
MaxRetries = 3 // 最大重试次数
|
||||
RetryDelay = 3 * time.Second // 重试延迟
|
||||
MinPartSize = 1 * 1024 * 1024 // 最小分片大小(1MB)
|
||||
)
|
||||
|
||||
// 错误定义
|
||||
var (
|
||||
ErrInvalidFileSize = errors.New("invalid file size")
|
||||
ErrTaskFailed = errors.New("download task failed")
|
||||
ErrIncompleteDownload = errors.New("incomplete download")
|
||||
)
|
||||
|
||||
// 进度回调函数
|
||||
type ProgressCallback func(totalDownloaded float64, totalSize float64, taskID int, taskProgress float64)
|
||||
|
||||
// 进度通道
|
||||
type ProgressChan struct {
|
||||
taskID int
|
||||
bytes int64
|
||||
}
|
||||
|
||||
// 下载任务
|
||||
type DownloadTask struct {
|
||||
taskID int
|
||||
rangeStart int64
|
||||
@@ -143,7 +132,7 @@ func (fd *FileDownloader) init() error {
|
||||
|
||||
fd.TotalSize = resp.ContentLength
|
||||
if fd.TotalSize <= 0 {
|
||||
return ErrInvalidFileSize
|
||||
return errors.New("invalid file size")
|
||||
}
|
||||
|
||||
if resp.Header.Get("Accept-Ranges") == "bytes" && fd.TotalSize > MinPartSize {
|
||||
|
||||
@@ -22,17 +22,17 @@ func (p *DefaultPlugin) Domains() []string {
|
||||
}
|
||||
|
||||
func (p *DefaultPlugin) OnRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
|
||||
return nil, nil
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (p *DefaultPlugin) OnResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||
if resp == nil || resp.Request == nil || (resp.StatusCode != 200 && resp.StatusCode != 206) {
|
||||
return nil
|
||||
return resp
|
||||
}
|
||||
|
||||
classify, suffix := p.bridge.TypeSuffix(resp.Header.Get("Content-Type"))
|
||||
if classify == "" {
|
||||
return nil
|
||||
return resp
|
||||
}
|
||||
|
||||
rawUrl := resp.Request.URL.String()
|
||||
@@ -74,5 +74,5 @@ func (p *DefaultPlugin) OnResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *
|
||||
}(res)
|
||||
}
|
||||
|
||||
return nil
|
||||
return resp
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ func (p *QqPlugin) OnRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Requ
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (p *QqPlugin) OnResponse(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||
|
||||
@@ -54,7 +54,7 @@ func init() {
|
||||
return resourceOnce.getResType(key)
|
||||
},
|
||||
TypeSuffix: func(mine string) (string, string) {
|
||||
return globalConfig.TypeSuffix(mine)
|
||||
return globalConfig.typeSuffix(mine)
|
||||
},
|
||||
MediaIsMarked: func(key string) bool {
|
||||
return resourceOnce.mediaIsMarked(key)
|
||||
@@ -145,21 +145,22 @@ func (p *Proxy) matchPlugin(host string) shared.Plugin {
|
||||
if plugin, ok := pluginRegistry[domain]; ok {
|
||||
return plugin
|
||||
}
|
||||
|
||||
return pluginRegistry["default"]
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Proxy) httpRequestEvent(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
|
||||
newReq, newResp := p.matchPlugin(r.Host).OnRequest(r, ctx)
|
||||
if newResp != nil {
|
||||
return newReq, newResp
|
||||
}
|
||||
plugin := p.matchPlugin(r.Host)
|
||||
if plugin != nil {
|
||||
newReq, newResp := plugin.OnRequest(r, ctx)
|
||||
if newResp != nil {
|
||||
return newReq, newResp
|
||||
}
|
||||
|
||||
if newReq != nil {
|
||||
return newReq, nil
|
||||
if newReq != nil {
|
||||
return newReq, nil
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
return pluginRegistry["default"].OnRequest(r, ctx)
|
||||
}
|
||||
|
||||
func (p *Proxy) httpResponseEvent(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response {
|
||||
@@ -167,10 +168,13 @@ func (p *Proxy) httpResponseEvent(resp *http.Response, ctx *goproxy.ProxyCtx) *h
|
||||
return resp
|
||||
}
|
||||
|
||||
newResp := p.matchPlugin(resp.Request.Host).OnResponse(resp, ctx)
|
||||
if newResp != nil {
|
||||
return newResp
|
||||
plugin := p.matchPlugin(resp.Request.Host)
|
||||
if plugin != nil {
|
||||
newResp := plugin.OnResponse(resp, ctx)
|
||||
if newResp != nil {
|
||||
return newResp
|
||||
}
|
||||
}
|
||||
|
||||
return resp
|
||||
return pluginRegistry["default"].OnResponse(resp, ctx)
|
||||
}
|
||||
|
||||
@@ -1,20 +1,5 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/elazarl/goproxy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Bridge struct {
|
||||
GetVersion func() string
|
||||
GetResType func(key string) (bool, bool)
|
||||
TypeSuffix func(mime string) (string, string)
|
||||
MediaIsMarked func(key string) bool
|
||||
MarkMedia func(key string)
|
||||
GetConfig func(key string) interface{}
|
||||
Send func(t string, data interface{})
|
||||
}
|
||||
|
||||
type MediaInfo struct {
|
||||
Id string
|
||||
Url string
|
||||
@@ -31,10 +16,3 @@ type MediaInfo struct {
|
||||
ContentType string
|
||||
OtherData map[string]string
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
SetBridge(*Bridge)
|
||||
Domains() []string
|
||||
OnRequest(*http.Request, *goproxy.ProxyCtx) (*http.Request, *http.Response)
|
||||
OnResponse(*http.Response, *goproxy.ProxyCtx) *http.Response
|
||||
}
|
||||
|
||||
23
core/shared/plugin.go
Normal file
23
core/shared/plugin.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/elazarl/goproxy"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type Bridge struct {
|
||||
GetVersion func() string
|
||||
GetResType func(key string) (bool, bool)
|
||||
TypeSuffix func(mime string) (string, string)
|
||||
MediaIsMarked func(key string) bool
|
||||
MarkMedia func(key string)
|
||||
GetConfig func(key string) interface{}
|
||||
Send func(t string, data interface{})
|
||||
}
|
||||
|
||||
type Plugin interface {
|
||||
SetBridge(*Bridge)
|
||||
Domains() []string
|
||||
OnRequest(*http.Request, *goproxy.ProxyCtx) (*http.Request, *http.Response)
|
||||
OnResponse(*http.Response, *goproxy.ProxyCtx) *http.Response
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
# res-downloader V3
|
||||
<div align="center">
|
||||
<a href="https://github.com/putyy/res-downloader"><img src="images/logo.png" width="120"/></a>
|
||||
<h1><strong>res-downloader</strong></h1>
|
||||
</div>
|
||||
|
||||
> 全新技术栈,更新、更小、更快、更稳
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
* [论坛](https://s.gowas.cn/d/4089)
|
||||
* [反馈](https://github.com/putyy/res-downloader/issues)
|
||||
* [日志](https://github.com/putyy/res-downloader/releases)
|
||||
* [QQ群](https://qm.qq.com/q/ImE37ayJmc)
|
||||
* [WX群](https://www.putyy.com/app/admin/upload/img/20250418/6801d9554dc7.webp)
|
||||
BIN
docs/images/logo.png
Executable file
BIN
docs/images/logo.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 120 KiB |
@@ -27,15 +27,13 @@
|
||||
subMaxLevel: 4,
|
||||
// 小屏设备下合并导航栏到侧边栏
|
||||
mergeNavbar: true,
|
||||
basePath: '/',
|
||||
homepage: 'readme.md',
|
||||
search: {
|
||||
maxAge: 86400000,// 过期时间,单位毫秒,默认一天
|
||||
paths: 'auto',// 注意:仅适用于 paths: 'auto' 模式
|
||||
placeholder: '搜索',
|
||||
// 支持本地化
|
||||
placeholder: {
|
||||
'/zh-cn/': '搜索',
|
||||
'/': 'Type to search'
|
||||
},
|
||||
placeholder: '搜索',
|
||||
noData: '找不到结果',
|
||||
depth: 4,
|
||||
hideOtherSidebarContent: false,
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
- 双击下载好的dmg文件,将res-downloader拖入应用即可,如图:
|
||||

|
||||
|
||||
## Linux安装过程
|
||||
- 执行文件运行方式举例
|
||||
## Linux安装过程(自行替换掉对应的安装文件目录)
|
||||
- ubuntu安装deb文件
|
||||
> sudo apt install res-downloader_3.0.2_linux_x64.deb
|
||||
|
||||
- 执行文件运行方式
|
||||
> chmod +x ./res-downloader_3.0.2_linux_x64
|
||||
> sudo ./res-downloader_3.0.2_linux_x64
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
## 隐藏功能
|
||||
- 导出\导入 数据,1秒内连续点击空白处5次即可开启(单次有效)
|
||||

|
||||
|
||||
## 清空列表、类型筛选
|
||||
- 当资源列表过大时,无法快速找到需要的资源,这时可以先清空列表再去刷新需要的资源页面
|
||||
- 资源列表过多,可以快速根据需要的资源类型进行筛选
|
||||
|
||||
@@ -1,15 +1,63 @@
|
||||
# res-downloader
|
||||
## 爱享素材下载器
|
||||
<div align="center">
|
||||
|
||||
🎯 基于Go + [wails](https://github.com/wailsapp/wails)
|
||||
📦 操作简单、可获取不同类型的网络资源
|
||||
🖥️ 支持Windows、Mac、Linux
|
||||
🌐 支持视频、音频、图片、m3u8、直播流等常见网络资源
|
||||
💪 支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源下载
|
||||
👼 支持设置代理以获取特殊网络下的资源
|
||||
<a href="https://github.com/putyy/res-downloader"><img src="images/logo.png" width="120"/></a>
|
||||
<h1>res-downloader</h1>
|
||||
<h4>📖 中文 | <a href="https://github.com/putyy/res-downloader/blob/master/README-EN.md">English</a></h4>
|
||||
|
||||
## 实现 & 初衷
|
||||
?> 通过设置系统网络代理拦截响应,筛选出需要的资源, 同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,只不过这些软件需要手动进行筛选,对于小白用户上手还是有点难度,本软件对部分资源做了特殊处理,更适合大众用户,所以就有了本项目。
|
||||
[](https://github.com/putyy/res-downloader/stargazers)
|
||||
[](https://github.com/putyy/res-downloader/fork)
|
||||
[](https://github.com/putyy/res-downloader/releases)
|
||||

|
||||
[](https://github.com/putyy/res-downloader/blob/master/LICENSE)
|
||||
|
||||
## 免责声明
|
||||
?> 本软件用于学习研究使用,若因使用本软件造成的一切法律责任均与本人无关!
|
||||
</div>
|
||||
|
||||
---
|
||||
|
||||
### 🎉 爱享素材下载器
|
||||
|
||||
> 一款基于 Go + [Wails](https://github.com/wailsapp/wails) 的跨平台资源下载工具,简洁易用,支持多种资源嗅探与下载。
|
||||
|
||||
## ✨ 功能特色
|
||||
|
||||
- 🚀 **简单易用**:操作简单,界面清晰美观
|
||||
- 🖥️ **多平台支持**:Windows / macOS / Linux
|
||||
- 🌐 **多资源类型支持**:视频 / 音频 / 图片 / m3u8 / 直播流等
|
||||
- 📱 **平台兼容广泛**:支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、QQ音乐等
|
||||
- 🌍 **代理抓包**:支持设置代理获取受限网络下的资源
|
||||
|
||||
## 📚 文档 & 版本
|
||||
|
||||
- 📘 [在线文档](https://res.putyy.com/)
|
||||
- 💬 [加入交流群](https://www.putyy.com/app/admin/upload/img/20250418/6801d9554dc7.webp)
|
||||
- 🧩 [最新版](https://github.com/putyy/res-downloader/releases) | [Mini版 使用默认浏览器展示UI](https://github.com/putyy/resd-mini) | [Electron旧版 支持Win7](https://github.com/putyy/res-downloader/tree/old)
|
||||
> *群满时可加微信 `AmorousWorld`,请备注“来源”*
|
||||
|
||||
## 🧩 下载地址
|
||||
|
||||
- 🆕 [GitHub 下载](https://github.com/putyy/res-downloader/releases)
|
||||
- 🆕 [蓝奏云下载(密码:9vs5)](https://wwjv.lanzoum.com/b04wgtfyb)
|
||||
- ⚠️ *Win7 用户请下载 `2.3.0` 版本*
|
||||
|
||||
|
||||
## 🖼️ 预览
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### 🧠 更多问题
|
||||
|
||||
- [GitHub Issues](https://github.com/putyy/res-downloader/issues)
|
||||
- [爱享论坛讨论帖](https://s.gowas.cn/d/4089)
|
||||
|
||||
## 💡 实现原理 & 初衷
|
||||
|
||||
本工具通过代理方式实现网络抓包,并筛选可用资源。与 Fiddler、Charles、浏览器 DevTools 原理类似,但对资源进行了更友好的筛选、展示和处理,大幅度降低了使用门槛,更适合大众用户使用。
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ 免责声明
|
||||
|
||||
> 本软件仅供学习与研究用途,禁止用于任何商业或违法用途。
|
||||
如因此产生的任何法律责任,概与作者无关!
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
## 视频号拦截了一大堆 找不到想要的
|
||||
> 设置里面关闭全量拦截,将视频转发好友后打开
|
||||
|
||||
## 某某网址拦截不了?
|
||||
> 本软件实现原理 & 初衷如下,并非万能的,所以有一些应用拦截不了很正常
|
||||
```
|
||||
本工具通过代理方式实现网络抓包,并筛选可用资源。与 Fiddler、Charles、浏览器 DevTools 原理类似,但对资源进行了更友好的筛选、展示和处理,大幅度降低了使用门槛,更适合大众用户使用。
|
||||
```
|
||||
|
||||
## 软件打不开了?之前可以打开
|
||||
> 删除对应目录, 然后重启
|
||||
```
|
||||
## Mac执行
|
||||
rm -rf /Users/$(whoami)/Library/Preferences/res-downloader
|
||||
|
||||
## Windows手动删除以下目录,Administrator为用户名 通常如下:
|
||||
C:\Users\Administrator\AppData\Roaming\res-downloader
|
||||
|
||||
## Linux手动删除以下目录
|
||||
/home/user/.config/res-downloader/home/user/.config/res-downloader
|
||||
```
|
||||
|
||||
## 某应用只支持手机打开 如何拦截?
|
||||
> 这里需要注意的是 应用使用http协议通讯才能拦截,且安卓7.0以上系统不再信任用户CA证书 所以没法拦截,解决方案自行查找,
|
||||
```
|
||||
1. 将手机和电脑处于同一个网络
|
||||
2. 在手机端安装res-downloader的证书
|
||||
3. 将手机网络代理设置为res-downloader的代理
|
||||
4. 正常使用
|
||||
```
|
||||
|
||||
## Mac 提示“已损坏,无法打开”, 打开命令行执行如下命令:
|
||||
> sudo xattr -d com.apple.quarantine /Applications/res-downloader.app
|
||||
|
||||
@@ -10,7 +41,7 @@
|
||||
> 手动关闭系统代理设置
|
||||
|
||||
## 链接不是私密链接
|
||||
> 通常是证书未正确安装,最新版证书下载:软件左下角?点击后有下载地址
|
||||
> 通常是证书未正确安装,最新版证书下载:软件左下角 ?点击后有下载地址
|
||||
> 根据自己系统进行安装证书操作(不懂的自行百度),手动安装需安装到受信任的根证书
|
||||
|
||||
- Mac手动安装证书(V3+版本支持),打开终端复制以下命令 粘贴到终端回车 按照提示输入密码,完成后再打开软件:
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"password_title": "管理员授权",
|
||||
"password_tip": "本次输入的密码仅在本次运行期间有效,用于安装证书或设置系统代理!",
|
||||
"password_placeholder": "请输入你的电脑密码",
|
||||
"password_cache": "是否缓存",
|
||||
"password_cache": "缓存密码",
|
||||
"password_empty": "密码不能为空",
|
||||
"screen_minimize": "最小化",
|
||||
"screen_restore": "还原",
|
||||
|
||||
Reference in New Issue
Block a user