15 Commits
3.0.2 ... 3.0.3

Author SHA1 Message Date
putyy
791e50411d Update issue templates 2025-02-11 21:45:52 +08:00
putyy
df8eb0e4cd Update issue templates 2025-02-11 21:44:28 +08:00
putyy
3e291171c2 Update issue templates 2025-02-11 21:43:48 +08:00
putyy
bd8f8e80c9 Merge pull request #143 from putyy/wails
Wails
2025-02-11 21:42:19 +08:00
putyy
8ed7e144e1 修改doc、优化Mac设置代理等 2025-02-11 21:40:29 +08:00
putyy
69f8224453 完善文档、新增一些功能 2025-02-10 15:40:32 +08:00
putyy
3c0e51a9e2 文档 2025-02-09 18:58:09 +08:00
putyy
0a6679b983 新增docsify 2025-02-08 17:29:36 +08:00
putyy
6d1024806c Merge pull request #131 from putyy/wails
Wails
2025-01-22 16:19:44 +08:00
putyy
388e3f46a4 更新md 2025-01-22 16:18:32 +08:00
putyy
f7c8e9f7db 更新host 2025-01-21 10:37:10 +08:00
putyy
7ca484f45d Merge pull request #130 from putyy/wails
up:wx rule、downloads
2025-01-14 14:16:21 +08:00
putyy
cecb13fa90 up:wx rule、downloads 2025-01-14 13:59:22 +08:00
putyy
331478d370 Merge pull request #127 from taotieren/update-aur
update README.md
2025-01-11 13:16:40 +08:00
taotieren
2481407093 update README.md 2025-01-11 11:45:37 +08:00
48 changed files with 530 additions and 72 deletions

44
.github/ISSUE_TEMPLATE /bug_report.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: Bug Report \ 问题反馈
description: Create a report to help us improve \ 帮助改进
labels: ["Bug"]
body:
- type: input
id: title
attributes:
label: Title \ 标题
description: A brief summary of the bug. \ 对于该错误的简要总结。
placeholder: Enter the bug title here. \ 在此输入错误标题。
validations:
required: true
- type: textarea
id: reproduce
attributes:
label: To Reproduce \ 操作流程
description: Steps to reproduce the behaviour. \ 重现该行为的步骤。
placeholder: |
1. Go to '...' \ 1. 进入 '...'
2. Click on '....' \ 2. 点击 '....'
3. Scroll down to '....' \ 3. 向下滚动到 '....'
4. See error \ 4. 查看错误
validations:
required: true
- type: textarea
id: expected-behaviour
attributes:
label: Expected Behaviour \ 预期结果
description: A clear and concise description of what you expected to happen. \ 对您期望发生的事情的清晰简明描述。
placeholder: A clear and concise description of what you expected to happen. \ 对您期望发生的事情的清晰简明描述。
validations:
required: true
- type: textarea
id: software-version
attributes:
label: Software Version \ 软件版本
description: Please specify the version of the software you are using. \ 请指定您使用的软件版本。
placeholder: Enter the software version here. \ 在此输入软件版本。
validations:
required: true

1
.github/ISSUE_TEMPLATE /config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: true

View File

@@ -0,0 +1,31 @@
name: Feature Request \ 功能建议
description: Suggest an idea for this project \ 为这个项目提出一个新想法
labels: ["Enhancement"]
body:
- type: input
id: title
attributes:
label: Title \ 标题
description: A brief summary of your feature request. \ 对您功能建议的简要总结。
placeholder: Enter the feature title here. \ 在此输入功能标题。
validations:
required: true
- type: textarea
id: feature-suggestion
attributes:
label: Feature Suggestion \ 功能建议
description: A clear and concise description of the feature you would like to suggest. \ 对您想要建议的功能的清晰简明描述。
placeholder: Describe your feature suggestion here. \ 在此描述您的功能建议。
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Proposed Solution \ 你的方案
description: A clear and concise description of your proposed solution. \ 对您提议的解决方案的清晰简明描述。
placeholder: Describe your proposed solution here. \ 在此描述您的提议方案。
validations:
required: true

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@ test
build/bin
node_modules
frontend/dist
.DS_Store

View File

@@ -1,5 +1,6 @@
## res-downloader V3全新版来袭、全新实现支持更多设置视频号、直播流、m3u8预览等
### 爱享素材下载器【[加入群聊](https://qm.qq.com/q/HS8FdhpZCK)】
## res-downloader
### 爱享素材下载器
🎯 基于Go + [wails](https://github.com/wailsapp/wails)
📦 操作简单、可获取不同类型资源
🖥️ 支持Windows、Mac、Linux
@@ -7,11 +8,13 @@
💪 支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源下载
👼 支持设置代理以获取特殊网络下的资源
## 软件下载(Win7下载2.3.0版本)
🆕 [github下载](https://github.com/putyy/res-downloader/releases)
🆕 [蓝奏云下载 密码:9vs5](https://wwjv.lanzoum.com/b04wgtfyb)
## [在线文档](https://res.putyy.com/)、[加入群聊](https://qm.qq.com/q/ImE37ayJmc)、[Electron版](https://github.com/putyy/res-downloader/tree/old)
## 使用方法
## 软件下载(Win7下载2.3.0版本)
🆕 [github下载](https://github.com/putyy/res-downloader/releases)
🆕 [蓝奏云下载 密码:9vs5](https://wwjv.lanzoum.com/b04wgtfyb)
## 使用方法
> 0. 安装时一定要同意安装证书文件、一定要允许网络访问
> 1. 打开本软件 软件首页左上角点击 “启动代理”
> 2. 软件首页选择要获取的资源类型(默认选中的全部)
@@ -19,7 +22,7 @@
> 4. 返回软件首页即可看到资源列表
## 软件截图
![](preview/show.webp)
![](docs/images/show.webp)
## 常见问题
m3u8: 预览和下载:

BIN
build/.DS_Store vendored

Binary file not shown.

View File

@@ -1,16 +1,14 @@
## Mac
```bash
wails build -platform "darwin/universal" --dmg-name
create-dmg 'build/bin/res-downloader.app' \
--overwrite --dmg-title="res-downloader" \
--dmg-name "res-downloader_$(jq -r '.info.productVersion' wails.json).dmg" \
./build/bin
wails build -platform "darwin/universal"
create-dmg 'build/bin/res-downloader.app' --overwrite ./build/bin
mv -f "build/bin/res-downloader $(jq -r '.info.productVersion' wails.json).dmg" "build/bin/res-downloader_$(jq -r '.info.productVersion' wails.json).dmg"
```
## Windows
```bash
wails build -f -nsis -platform "windows/amd64" -webview2 Embed
wails build -f -nsis -platform "windows/arm64" -webview2 Embed
wails build -f -nsis -platform "windows/amd64" -webview2 Embed && mv -f "build/bin/res-downloader-amd64-installer.exe" "build/bin/res-downloader_$(jq -r '.info.productVersion' wails.json)_win_x64.exe"
wails build -f -nsis -platform "windows/arm64" -webview2 Embed && mv -f "build/bin/res-downloader-arm64-installer.exe" "build/bin/res-downloader_$(jq -r '.info.productVersion' wails.json)_win_arm.exe"
```
## Linux
@@ -59,17 +57,26 @@ echo "$(cat build/linux/Debian/DEBIAN/.control | sed -e "s/{{Version}}/$(jq -r '
dpkg-deb --build ./build/linux/Debian build/bin/res-downloader_$(jq -r '.info.productVersion' wails.json)_arm.deb
```
> ArchLinux环境
> 安装
> yay -Syu res-downloader
### Arch Linux
[![Packaging status](https://repology.org/badge/vertical-allrepos/res-downloader.svg)](https://repology.org/project/res-downloader/versions)
>
```bash
yay -Syu res-downloader
```
### Linux 本地编译
```bash
git clone https://github.com/putyy/res-downloader.git
cd res-downloader
# -- GO Proxy --
# 如果国内编译时 go 下载慢或报错,可以设置 go 国内代理加速,否则不用设置
export GO111MODULE=on
export GOPROXY=https://goproxy.cn,direct
# -- Go Proxy --
wails build
cd build
sudo install -Dvm755 bin/res-downloader -t /usr/bin
sudo install -Dvm644 appicon.png /usr/share/icons/hicolor/512x512/apps/res-downloader.png
sudo install -Dvm644 linux/res-downloader.desktop /usr/share/applications/res-downloader.desktop
```
sudo install -Dvm644 build/linux/Arch/res-downloader.desktop /usr/share/applications/res-downloader.desktop
```

View File

@@ -0,0 +1,8 @@
[Desktop Entry]
Type=Application
Name=res-downloader
Comment=This is a high-value and high-performance and diverse resource downloader called res-downloader
Exec=res-downloader
Icon=res-downloader.png
Terminal=false
Categories=Utility;

View File

@@ -14,7 +14,7 @@
!define INFO_PRODUCTNAME "res-downloader"
!endif
!ifndef INFO_PRODUCTVERSION
!define INFO_PRODUCTVERSION "3.0.2"
!define INFO_PRODUCTVERSION "3.0.3"
!endif
!ifndef INFO_COPYRIGHT
!define INFO_COPYRIGHT "Copyright © 2023"

View File

@@ -7,6 +7,7 @@ import (
"github.com/wailsapp/wails/v2/pkg/runtime"
"os"
"path/filepath"
"regexp"
sysRuntime "runtime"
"strconv"
"strings"
@@ -37,12 +38,18 @@ var (
httpServerOnce *HttpServer
)
func GetApp(assets embed.FS) *App {
func GetApp(assets embed.FS, wjs string) *App {
if appOnce == nil {
matches := regexp.MustCompile(`"productVersion":\s*"([\d.]+)"`).FindStringSubmatch(wjs)
version := "1.0.1"
if len(matches) > 0 {
version = matches[1]
}
appOnce = &App{
assets: assets,
AppName: "res-downloader",
Version: "3.0.2",
Version: version,
Description: "res-downloader是一款集网络资源嗅探 + 高速下载功能于一体的软件,高颜值、高性能和多样化,提供个人用户下载自己上传到各大平台的网络资源功能!",
Copyright: "Copyright © 2023~" + strconv.Itoa(time.Now().Year()),
PublicCrt: []byte(`
@@ -168,7 +175,7 @@ func (a *App) OpenSystemProxy() bool {
a.IsProxy = true
return true
}
DialogErr("设置失败" + err.Error())
DialogErr("设置失败:" + err.Error())
return false
}
@@ -181,7 +188,7 @@ func (a *App) UnsetSystemProxy() bool {
a.IsProxy = false
return true
}
DialogErr("设置失败")
DialogErr("设置失败:" + err.Error())
return false
}

View File

@@ -15,6 +15,8 @@ type Config struct {
Port string `json:"Port"`
Quality int `json:"Quality"`
SaveDirectory string `json:"SaveDirectory"`
FilenameLen int `json:"FilenameLen"`
FilenameTime bool `json:"FilenameTime"`
UpstreamProxy string `json:"UpstreamProxy"`
OpenProxy bool `json:"OpenProxy"`
DownloadProxy bool `json:"DownloadProxy"`
@@ -28,15 +30,17 @@ func initConfig() *Config {
if globalConfig == nil {
def := `
{
"Host": "0.0.0.0",
"Host": "127.0.0.1",
"Port": "8899",
"Theme": "lightTheme",
"Quality": 0,
"SaveDirectory": "",
"FilenameLen": 0,
"FilenameTime": true,
"UpstreamProxy": "",
"OpenProxy": false,
"DownloadProxy": false,
"AutoProxy": false,
"AutoProxy": true,
"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"
@@ -64,6 +68,8 @@ func (c *Config) setConfig(config Config) {
c.Theme = config.Theme
c.Quality = config.Quality
c.SaveDirectory = config.SaveDirectory
c.FilenameLen = config.FilenameLen
c.FilenameTime = config.FilenameTime
c.UpstreamProxy = config.UpstreamProxy
c.UserAgent = config.UserAgent
c.OpenProxy = config.OpenProxy

View File

@@ -83,6 +83,10 @@ func (fd *FileDownloader) init() error {
fd.TotalSize = resp.ContentLength
if fd.TotalSize <= 0 {
return fmt.Errorf("invalid file")
}
if resp.Header.Get("Accept-Ranges") == "bytes" && fd.TotalSize > 10485760 {
fd.IsMultiPart = true
}
@@ -90,21 +94,21 @@ func (fd *FileDownloader) init() error {
resp.Body.Close()
fd.FileName = filepath.Clean(fd.FileName)
_, err = os.Stat(fd.FileName)
if err != nil {
if os.IsNotExist(err) {
fd.File, err = os.Create(fd.FileName)
if err != nil && fd.TotalSize > 0 {
err = fd.File.Truncate(fd.TotalSize)
}
}
} else {
fd.File, err = os.OpenFile(fd.FileName, os.O_RDWR, os.ModeAppend)
}
if err != nil {
dir := filepath.Dir(fd.FileName)
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return err
}
fd.File, err = os.OpenFile(fd.FileName, os.O_RDWR|os.O_CREATE, 0644)
if err != nil {
return fmt.Errorf("文件初始化失败: %w", err)
}
if err = fd.File.Truncate(fd.TotalSize); err != nil {
fd.File.Close()
return fmt.Errorf("文件大小设置失败: %w", err)
}
return nil
}

View File

@@ -175,6 +175,12 @@ func (p *Proxy) handleWechatRequest(r *http.Request, ctx *goproxy.ProxyCtx) (*ht
ContentType: "video/mp4",
}
if mediaType, ok := firstMedia["mediaType"].(float64); ok && mediaType == 9 {
res.Classify = "image"
res.Suffix = ".png"
res.ContentType = "image/png"
}
if urlToken, ok := firstMedia["urlToken"].(string); ok {
res.Url = res.Url + urlToken
}

View File

@@ -113,13 +113,22 @@ func (r *Resource) download(mediaInfo MediaInfo, decodeStr string) {
fileName := Md5(rawUrl)
if mediaInfo.Description != "" {
fileName = regexp.MustCompile(`[^\w\p{Han}]`).ReplaceAllString(mediaInfo.Description, "")
fileLen := globalConfig.FilenameLen
if fileLen <= 0 {
fileLen = 10
}
runes := []rune(fileName)
if len(runes) > 10 {
fileName = string(runes[:10])
if len(runes) > fileLen {
fileName = string(runes[:fileLen])
}
}
mediaInfo.SavePath = filepath.Join(globalConfig.SaveDirectory, fileName+"_"+GetCurrentDateTimeFormatted()+mediaInfo.Suffix)
if globalConfig.FilenameTime {
mediaInfo.SavePath = filepath.Join(globalConfig.SaveDirectory, fileName+"_"+GetCurrentDateTimeFormatted()+mediaInfo.Suffix)
} else {
mediaInfo.SavePath = filepath.Join(globalConfig.SaveDirectory, fileName+mediaInfo.Suffix)
}
if strings.Contains(rawUrl, "qq.com") {
if globalConfig.Quality == 1 &&

View File

@@ -18,15 +18,32 @@ func (s *SystemSetup) getNetworkServices() ([]string, error) {
services := strings.Split(string(output), "\n")
var validServices []string
var activeServices []string
for _, service := range services {
service = strings.TrimSpace(service)
if service != "" && !strings.Contains(service, "*") && !strings.Contains(service, "Serial Port") {
validServices = append(validServices, service)
if service == "" || strings.Contains(service, "*") || strings.Contains(service, "Serial Port") {
continue
}
// 检查服务是否活动
infoCmd := exec.Command("networksetup", "-getinfo", service)
infoOutput, err := infoCmd.Output()
if err != nil {
fmt.Printf("failed to get info for service %s: %v\n", service, err)
continue
}
// 如果输出中包含 "IP address:",说明服务是活动的
if strings.Contains(string(infoOutput), "IP address:") {
activeServices = append(activeServices, service)
}
}
return validServices, nil
if len(activeServices) == 0 {
return nil, fmt.Errorf("no active network services found")
}
return activeServices, nil
}
func (s *SystemSetup) setProxy() error {
@@ -34,9 +51,6 @@ func (s *SystemSetup) setProxy() error {
if err != nil {
return err
}
if len(services) == 0 {
return fmt.Errorf("find to Network failed")
}
is := false
for _, serviceName := range services {
@@ -56,7 +70,7 @@ func (s *SystemSetup) setProxy() error {
return nil
}
return fmt.Errorf("find to Network failed")
return fmt.Errorf("failed to set proxy for any active network service")
}
func (s *SystemSetup) unsetProxy() error {
@@ -64,9 +78,6 @@ func (s *SystemSetup) unsetProxy() error {
if err != nil {
return err
}
if len(services) == 0 {
return fmt.Errorf("find to Network failed")
}
is := false
for _, serviceName := range services {
@@ -86,7 +97,7 @@ func (s *SystemSetup) unsetProxy() error {
return nil
}
return fmt.Errorf("find to Network failed")
return fmt.Errorf("failed to set proxy for any active network service")
}
func (s *SystemSetup) installCert() (string, error) {

0
docs/.nojekyll Normal file
View File

9
docs/_coverpage.md Normal file
View File

@@ -0,0 +1,9 @@
# res-downloader V3
> 全新技术栈,更新、更小、更快、更稳
### 简单、高效、轻便 (仅 ~10M)
[开始使用 Let Go](/readme.md)
[下载](/getting-started.md)

4
docs/_navbar.md Normal file
View File

@@ -0,0 +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)

6
docs/_sidebar.md Normal file
View File

@@ -0,0 +1,6 @@
* [简介](readme.md)
* [快速开始](getting-started.md)
* [安装指南](installation.md)
* [功能演示](examples.md)
* [更多说明](more.md)
* [常见问题](troubleshooting.md)

19
docs/examples.md Normal file
View File

@@ -0,0 +1,19 @@
## 开启代理
- 安装完成后开启代理,如图:
![](images/examples-1.png ':size=50%')
## 拦截资源
### 视频号
- 打开视频号即可看到本软件中拦截到的资源
![](images/examples-2.webp ':size=50%')
### 网页资源
- 浏览器打开或者其他软件内置浏览器打开的网页
- 这里演示打开百度这个网站https://www.baidu.com/
![](images/examples-4.png ':size=50%')
### 小程序、公众号、抖音、小红书、qq音乐、酷狗等应用内资源获取方式都差不多
## 下载资源到本地
- 选择你想下载的视频 点击下载即可
![](images/examples-3.png ':size=50%')

BIN
docs/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

14
docs/getting-started.md Normal file
View File

@@ -0,0 +1,14 @@
## 软件下载
🆕 [github下载](https://github.com/putyy/res-downloader/releases)
🆕 [蓝奏云下载 密码:9vs5](https://wwjv.lanzoum.com/b04wgtfyb)
!> Win7用户请使用2.3.0版本
## 使用方法
- 安装时一定要同意安装证书文件、一定要允许网络访问
- 打开本软件(win系统首次使用管理员打开-鼠标右键选择管理员打开)
- 打开后,左上角点击 “启动代理”
- 打开要捕获的源, 如:视频号、网页、小程序等等
- 返回软件首页即可看到资源列
![](images/show.webp ':size=50%')

BIN
docs/images/config.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

BIN
docs/images/examples-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

BIN
docs/images/examples-2.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
docs/images/examples-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

BIN
docs/images/examples-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

BIN
docs/images/more-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
docs/images/more-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
docs/images/more-3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
docs/images/more-4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

52
docs/index.html Normal file
View File

@@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>res-downloader</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="keywords" content="res-downloader,视频号下载,抖音下载,快手下载,小红书下载,万能下载器,爱享素材,爱享素材下载器">
<meta name="description" content="res-downloader是一款集网络资源嗅探 + 高速下载功能于一体的软件,高颜值、高性能和多样化,提供个人用户下载自己上传到各大平台的网络资源功能!">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'res-downloader',
repo: 'https://github.com/putyy/res-downloader',
// 侧边栏支持默认加载的是项目根目录下的_sidebar.md文件
loadSidebar: true,
// 导航栏支持默认加载的是项目根目录下的_navbar.md文件
loadNavbar: true,
// 封面支持默认加载的是项目根目录下的_coverpage.md文件
coverpage: true,
// 最大支持渲染的标题层级
maxLevel: 5,
// 自定义侧边栏后默认不会再生成目录设置生成目录的最大层级建议配置为2-4
subMaxLevel: 4,
// 小屏设备下合并导航栏到侧边栏
mergeNavbar: true,
search: {
maxAge: 86400000,// 过期时间,单位毫秒,默认一天
paths: 'auto',// 注意:仅适用于 paths: 'auto' 模式
placeholder: '搜索',
// 支持本地化
placeholder: {
'/zh-cn/': '搜索',
'/': 'Type to search'
},
noData: '找不到结果',
depth: 4,
hideOtherSidebarContent: false,
namespace: 'Docsify-Guide',
}
}
</script>
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/emoji.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
</body>
</html>

18
docs/installation.md Normal file
View File

@@ -0,0 +1,18 @@
## 下载安装文件
- windows下载.exe结尾的根据自己的系统架构下载合适的安装文件通常下载带有“x64-installer.exe”结尾的文件
- Mac下载.dmg结尾即可
- Linux根据系统类型下载对应的执行文件或安装文件
## Windows安装过程
- 双击下载好的exe 正常安装即可,首次打开记得右键管理员运行
## Mac安装过程
- 双击下载好的dmg文件将res-downloader拖入应用即可如图:
![installation-mac-1.png](images/installation-mac-1.png ':size=50%')
## Linux安装过程
- 执行文件运行方式举例
> chmod +x ./res-downloader_3.0.2_linux_x64
> sudo ./res-downloader_3.0.2_linux_x64

21
docs/more.md Normal file
View File

@@ -0,0 +1,21 @@
## 隐藏功能
- 导出\导入 数据1秒内连续点击空白处5次即可开启(单次有效)
![more-4.png](images/more-4.png ':size=30%')
## 清空列表、类型筛选
- 当资源列表过大时,无法快速找到需要的资源,这时可以先清空列表再去刷新需要的资源页面
- 资源列表过多,可以快速根据需要的资源类型进行筛选
![more-4.png](images/more-1.png ':size=30%')
## 拦截想要的资源类型、批量下载
- 比如只需要视频时就选择视频类型,可以多选
![more-1.png](images/more-2.png ':size=30%')
## 复制链接、视频解密
- 复制链接可用于第三方软件进行下载,下载完成后对该视频解密,点击“视频解密”选择用其他软件下载完成后的视频文件进行解密
![more-3.png](images/more-3.png ':size=30%')
## 设置说明
!> 修改完成后记得点保存
- 几乎每项配置在软件中都有说明(鼠标悬浮在?处即可查看),此处就不进行多余讲解
![config.png](images/config.png ':size=30%')

15
docs/readme.md Normal file
View File

@@ -0,0 +1,15 @@
# res-downloader
## 爱享素材下载器
🎯 基于Go + [wails](https://github.com/wailsapp/wails)
📦 操作简单、可获取不同类型的网络资源
🖥️ 支持Windows、Mac、Linux
🌐 支持视频、音频、图片、m3u8、直播流等常见网络资源
💪 支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源下载
👼 支持设置代理以获取特殊网络下的资源
## 实现 & 初衷
?> 通过设置系统网络代理拦截响应,筛选出需要的资源, 同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的只不过这些软件需要手动进行筛选对于小白用户上手还是有点难度本软件对部分资源做了特殊处理更适合大众用户所以就有了本项目。
## 免责声明
?> 本软件用于学习研究使用,若因使用本软件造成的一切法律责任均与本人无关!

46
docs/troubleshooting.md Normal file
View File

@@ -0,0 +1,46 @@
## Mac 提示“已损坏,无法打开”, 打开命令行执行如下命令:
> sudo xattr -d com.apple.quarantine /Applications/res-downloader.app
## 打开本软件,无法正常拦截获取
> 检查系统证书是否安装
> 关闭网络防火墙
> 系统代理是否正确设置(代理地址127.0.0.1 端口8899)
## 关闭软件后无法正常上网
> 手动关闭系统代理设置
## 链接不是私密链接
> 通常是证书未正确安装,最新版证书下载:软件左下角?点击后有下载地址
> 根据自己系统进行安装证书操作(不懂的自行百度),手动安装需安装到受信任的根证书
- Mac手动安装证书(V3+版本支持),打开终端复制以下命令 粘贴到终端回车 按照提示输入密码,完成后再打开软件:
```shell
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain /Users/$(whoami)/Library/Preferences/res-downloader/cert.crt && touch /Users/$(whoami)/Library/Preferences/res-downloader/install.lock && echo "安装完成"
```
## 拦截不到小程序中的资源
清理微信缓存,删除小程序后,重新打开
> 设置->存储空间->缓存
## 只拦截打开的视频号视频
关闭全量拦截,打开视频号视频详情,通常分享好友后打开的页面属于详情页
## 拦截视频号账号视频
打开对应作者个人主页,浏览即可
## 下载慢、大视频下载失败
推荐使用如下工具加速下载,视频号可以下载完成后再到对应视频操作项选择 “视频解密” 按钮
> [Neat Download Manager](https://www.neatdownloadmanager.com/index.php/en/)、[Motrix](https://motrix.app/download)等软件进行下载
## 直播流: 预览和录制:
> [使用obs进行预览和录制 使用教程自行百度, 点击下载obs]( https://obsproject.com/)
## m3u8: 预览和下载:
> [在线下载](https://m3u8-down.gowas.cn/)、[在线预览](https://m3u8play.com/)
## 安装证书后还会提示安装
使用命令行打开本软件,查看 “lockfile:” 这串字符后面的锁文件路径,然后创建该文件即可
例如 mac系统下终端执行如下命令即可创建
> touch /Users/你的用户名/Library/Preferences/res-downloader/install.lock
## 更多问题 请前往github进行[反馈](https://github.com/putyy/res-downloader/issues)

View File

@@ -8,6 +8,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
Footer: typeof import('./src/components/Footer.vue')['default']
ImportJson: typeof import('./src/components/ImportJson.vue')['default']
Index: typeof import('./src/components/layout/Index.vue')['default']
NaiveProvider: typeof import('./src/components/NaiveProvider.vue')['default']
NButton: typeof import('naive-ui')['NButton']

Binary file not shown.

View File

@@ -0,0 +1,36 @@
<template>
<NModal
:show="showModal"
:on-update:show="changeShow"
style="--wails-draggable:no-drag"
preset="card"
class="w-[640px]"
title="导入数据"
>
<NForm
size="medium"
label-placement="left"
label-width="auto"
require-mark-placement="right-hanging"
style="--wails-draggable:no-drag"
>
<NFormItem>
<NInput type="textarea" v-model:value="content" rows="8" :autosize="false" placeholder="添加多个时,请确保每行只有一个(每个链接回车换行)"></NInput>
</NFormItem>
<NFormItem>
<NButton strong secondary type="success" @click="emits('submit', content)" class="w-20">提交</NButton>
</NFormItem>
</NForm>
</NModal>
</template>
<script setup lang="ts">
import {ref} from "vue"
const content = ref("")
const props = defineProps<{
showModal: boolean
}>()
const emits = defineEmits(["update:showModal", "submit"])
const changeShow = (value: boolean) => emits("update:showModal", value)
</script>

View File

@@ -12,6 +12,9 @@
<NButton v-if="row.DecodeKey" type="warning" :tertiary="true" size="small" @click="action('decode')">
视频解密
</NButton>
<NButton v-if="isDebug" type="info" :tertiary="true" size="small" @click="action('json')">
复制数据
</NButton>
<NButton type="error" :tertiary="true" size="small" @click="action('delete')">
删除
</NButton>
@@ -19,6 +22,7 @@
</template>
<script setup lang="ts">
import {inject} from "vue"
const props = defineProps<{
row: any,
@@ -27,6 +31,8 @@ const props = defineProps<{
const emits = defineEmits(["action"])
const isDebug = inject('isDebug')
const action = (type: string) => {
emits('action', props.row, props.index, type)
}

View File

@@ -19,6 +19,8 @@ export const useIndexStore = defineStore("index-store", () => {
Quality: 0,
SaveDirectory: "",
UpstreamProxy: "",
FilenameLen: 0,
FilenameTime: false,
OpenProxy: false,
DownloadProxy: false,
AutoProxy: false,

View File

@@ -12,6 +12,8 @@ export namespace appType {
Port: string
Quality: number
SaveDirectory: string
FilenameLen: number
FilenameTime: boolean
UpstreamProxy: string
OpenProxy: boolean
DownloadProxy: boolean

View File

@@ -1,12 +1,13 @@
<template>
<div class="flex flex-col px-5 py-5">
<div class="pb-2 z-40">
<div class="pb-2 z-40" @click="triggerEvent">
<NSpace>
<NButton v-if="isProxy" secondary type="primary" @click="close" style="--wails-draggable:no-drag">关闭代理</NButton>
<NButton v-else tertiary type="tertiary" @click="open" style="--wails-draggable:no-drag">开启代理</NButton>
<NButton tertiary type="info" @click="batchDown" style="--wails-draggable:no-drag">批量下载</NButton>
<NButton tertiary type="error" @click="clear" 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 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>
<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>
</NSpace>
</div>
<div class="flex-1">
@@ -25,12 +26,13 @@
</div>
<Preview v-model:showModal="showPreviewRow" :previewRow="previewRow"/>
<ShowLoading :loadingText="loadingText" :isLoading="loading"/>
<ImportJson v-model:showModal="showImport" @submit="handleImport"/>
</div>
</template>
<script lang="ts" setup>
import {NButton, NImage, NTooltip} from "naive-ui"
import {computed, h, onMounted, ref, watch} from "vue"
import {computed, h, onMounted, ref, watch, provide} from "vue"
import type {appType} from "@/types/app"
import type {DataTableRowKey, ImageRenderToolbarProps} from "naive-ui"
@@ -42,23 +44,19 @@ import {useIndexStore} from "@/stores"
import appApi from "@/api/app"
import {DwStatus} from "@/const"
import ResAction from "@/components/ResAction.vue"
import ImportJson from "@/components/ImportJson.vue"
import {useEventStore} from "@/stores/event"
import {BrowserOpenURL, ClipboardSetText} from "../../wailsjs/runtime"
const eventStore = useEventStore()
const isProxy = computed(() => {
return store.isProxy
})
const data = ref<any[]>([])
const store = useIndexStore()
const tableHeight = computed(() => {
return store.tableHeight - 132
})
const resourcesType = ref<string[]>(["all"])
const options = [
{
@@ -216,12 +214,17 @@ const columns = ref<any[]>([
}
])
const downIndex = ref(0)
const checkedRowKeysValue = ref<DataTableRowKey[]>([])
const showPreviewRow = ref(false)
const previewRow = ref<appType.MediaInfo>()
const loading = ref(false)
const loadingText = ref("")
const isDebug = ref(false)
const showImport = ref(false)
let clickCount = 0
let clickTimeout: any = null
provide('isDebug', isDebug);
onMounted(() => {
const temp = localStorage.getItem("resources-type")
@@ -297,6 +300,15 @@ const dataAction = (row: appType.MediaInfo, index: number, type: string) => {
}
})
break
case "json":
ClipboardSetText(encodeURIComponent(JSON.stringify(row))).then((is: boolean) => {
if (is) {
window?.$message?.success("复制成功")
} else {
window?.$message?.error("复制失败")
}
})
break
case "open":
BrowserOpenURL(row.Url)
break;
@@ -444,4 +456,39 @@ 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)=>{
content.split("\n").forEach((line, index) => {
try {
let res = JSON.parse(decodeURIComponent(line))
if (res && res?.Id) {
res.Id = res.Id + Math.floor(Math.random() * 100000)
res.SavePath = ""
res.Status = "ready"
data.value.unshift(res)
}
}catch (e) {
console.log(e)
}
});
localStorage.setItem("resources-data", JSON.stringify(data.value))
showImport.value = false
}
</script>

View File

@@ -10,7 +10,7 @@
class="px-5 py-5"
>
<NFormItem label="代理Host" path="Port" size="small">
<NInput v-model:value="formValue.Host" placeholder="0.0.0.0" style="width:256px"/>
<NInput v-model:value="formValue.Host" placeholder="127.0.0.1" style="width:256px"/>
<NTooltip trigger="hover">
<template #trigger>
<NIcon size="20" class="pl-1">
@@ -37,6 +37,25 @@
<NButton strong secondary type="success" @click="selectDir">选择</NButton>
</NSpace>
</NFormItem>
<NFormItem label="文件命名" path="FilenameLen" size="small">
<NInputNumber v-model:value="formValue.FilenameLen" :min="0" :max="9999" placeholder="0" style="width:256px"/>
<NSwitch class="pl-1" v-model:value="formValue.FilenameTime" aria-placeholder="随机数">
<template #checked>
</template>
<template #unchecked>
</template>
</NSwitch>
<NTooltip trigger="hover">
<template #trigger>
<NIcon size="20" class="pl-1">
<HelpCircleOutline />
</NIcon>
</template>
<span>输入框控制文件命名的长度(不含时间0为无效此选项有描述信息时有效)开关控制文件末尾是否添加时间标识</span>
</NTooltip>
</NFormItem>
<NFormItem label="主题" path="theme" size="small">
<NRadio :checked="formValue.Theme === 'lightTheme'" value="lightTheme" name="theme" @change="handleChange">浅色主题</NRadio>
<NRadio :checked="formValue.Theme === 'darkTheme'" value="darkTheme" name="theme" @change="handleChange">深色主题</NRadio>
@@ -76,6 +95,7 @@
</NFormItem>
<NFormItem label="上游代理" path="UpstreamProxy" size="small">
<NInput v-model:value="formValue.UpstreamProxy" placeholder="例如: http://127.0.0.1:7890" style="width:256px"/>
<NSwitch class="pl-1" v-model:value="formValue.OpenProxy" />
<NTooltip trigger="hover">
<template #trigger>
<NIcon size="20" class="pl-1">
@@ -85,9 +105,6 @@
<span>可结合其他代理工具用于访问国外网站以及正常网络无法访问的资源(格式http://username:password@your.proxy.server:port)</span>
</NTooltip>
</NFormItem>
<NFormItem label="开启代理" path="OpenProxy" size="small">
<NSwitch v-model:value="formValue.OpenProxy" />
</NFormItem>
<NFormItem label="下载代理" path="DownloadProxy" size="small">
<NSwitch v-model:value="formValue.DownloadProxy" />
<NTooltip trigger="hover">

View File

@@ -23,9 +23,12 @@ var assets embed.FS
//go:embed build/appicon.png
var icon []byte
//go:embed wails.json
var wailsJson string
func main() {
// Create an instance of the app structure
app := core.GetApp(assets)
app := core.GetApp(assets, wailsJson)
isMac := runtime.GOOS == "darwin"
// menu
appMenu := menu.NewMenu()
@@ -58,6 +61,8 @@ func main() {
|_| \___| |___/ \__,_| \___/ \_/\_/ |_| |_| |_| \___/ \__ ,_| \__,_| \___| |_|`
log.Println(logo)
fmt.Println("version", app.Version)
fmt.Println("lockfile:", app.LockFile)
app.Startup(ctx)
},
OnShutdown: func(ctx context.Context) {

View File

@@ -13,7 +13,7 @@
"info": {
"companyName": "res-downloader",
"productName": "res-downloader",
"productVersion": "3.0.2",
"productVersion": "3.0.3",
"copyright": "Copyright © 2023",
"comments": "This is a high-value, high-performance, and diverse resource downloader called res-downloader."
}