mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-13 06:54:56 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
240bae9be9 | ||
|
|
46b1592a7f | ||
|
|
1cae714fd2 | ||
|
|
5e63624955 | ||
|
|
7584156262 | ||
|
|
d23c09748b | ||
|
|
936adca3f2 | ||
|
|
37424da698 | ||
|
|
7fd4877087 | ||
|
|
619ac47962 | ||
|
|
6b79585564 | ||
|
|
c1f05876e3 | ||
|
|
2981518cf4 | ||
|
|
511111f874 | ||
|
|
ca718deaad | ||
|
|
7a01544323 | ||
|
|
3082faaadc | ||
|
|
366c79fff2 | ||
|
|
525c8bb5a3 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -9,6 +9,8 @@ lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
temp
|
||||
test
|
||||
dist-ssr
|
||||
dist-electron
|
||||
release
|
||||
@@ -27,5 +29,5 @@ release
|
||||
|
||||
# lockfile
|
||||
package-lock.json
|
||||
pnpm-lock.yaml
|
||||
yarn.lock
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
59
README.md
59
README.md
@@ -1,16 +1,50 @@
|
||||
# res-downloader
|
||||
|
||||
## res-downloader
|
||||
### 爱享素材下载器【[加入群聊](https://qm.qq.com/q/mfDMSpCxQ4)】
|
||||
🎯 基于 [electron-vite-vue](https://github.com/electron-vite/electron-vite-vue.git)
|
||||
📦 操作简单、可获取不同类型的资源
|
||||
💪 支持获取视频、音频、图片、m3u8
|
||||
🖥 支持获取视频号、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源
|
||||
📦 操作简单、可获取不同类型的资源
|
||||
🖥️ 支持Win10、Win11、Mac、Linux
|
||||
🌐 支持视频、音频、图片、m3u8、直播流等常见网络资源拦截
|
||||
💪 支持微信视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐等网络资源下载
|
||||
👼 支持设置代理以获取特殊网络下的资源
|
||||
|
||||
## 软件下载
|
||||
🆕 [github下载](https://github.com/putyy/res-downloader/releases)
|
||||
🆕 [蓝奏云下载 密码:9vs5](https://wwjv.lanzoum.com/b04wgtfyb)
|
||||
|
||||
## 使用方法
|
||||
> 0. 安装一定要同意安装证书文件,安装一定要同意安装证书文件,安装一定要同意安装证书文件!
|
||||
> 1. 打开本软件
|
||||
> 2. 软件首页选择要获取的资源类型(默认选中的视频)
|
||||
> 3. 打开要捕获的源, 如:视频号、网页、小程序等等
|
||||
> 4. 返回软件首页即可看到资源列表
|
||||
|
||||
## 软件截图
|
||||

|
||||
|
||||
## 常见问题
|
||||
下载慢、大视频下载失败(最新版本以内置aria2下载器)
|
||||
> 推荐使用如下工具加速下载,视频号可以下载完成后再到对应视频操作项选择 “视频解密(视频号)” 按钮
|
||||
>> [Neat Download Manager](https://www.neatdownloadmanager.com/index.php/en/)、[Motrix](https://motrix.app/download)等软件进行下载
|
||||
|
||||
Win7无法使用
|
||||
> 软件不支持,也无计划支持
|
||||
|
||||
打开本软件,无法正常拦截获取
|
||||
> 检查系统代理是否正确设置 代理地址:127.0.0.1 端口:8899
|
||||
|
||||
关闭软件后无法正常上网
|
||||
> 手动关闭系统代理设置
|
||||
|
||||
打开本软件后无法上网
|
||||
> 手动删除安装标识锁文件,之后再打开软件会进行检查证书是否正确安装
|
||||
>> MAC: /Users/你的用户名称/.res-downloader@putyy/res-downloader-installed.lock
|
||||
>> Win: C:\Users\Admin\.res-downloader@putyy/res-downloader-installed.lock
|
||||
|
||||
其他问题
|
||||
[github](https://github.com/putyy/res-downloader/issues) 、 [爱享论坛](https://s.gowas.cn/d/4089)
|
||||
|
||||
## 二次开发
|
||||
> ps: 打包慢的问题可以参考 https://www.putyy.com/articles/87
|
||||
```sh
|
||||
git clone https://github.com/putyy/res-downloader
|
||||
|
||||
@@ -21,19 +55,14 @@ yarn install
|
||||
yarn run dev
|
||||
|
||||
# 打包mac
|
||||
yarn run build --mac
|
||||
yarn run build --universal --mac
|
||||
|
||||
# 打包win
|
||||
yarn run build --win
|
||||
```
|
||||
|
||||
## 软件截图
|
||||

|
||||
## 实现&初衷
|
||||
通过代理网络抓包拦截响应,筛选出有用的资源, 同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,只不过这些软件需要手动进行筛选,对于小白用户上手还是有点难度,本软件对部分资源做了特殊处理,更适合大众用户,所以就有了本项目。
|
||||
|
||||
## 实现原理
|
||||
> 通过代理网络抓包拦截响应,筛选出有用的资源,同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,只不过这些软件需要手动进行筛选,对于小白用户上手还是有点难度,所以就有了本项目这样的软件。
|
||||
|
||||
|
||||
## 参考项目
|
||||
|
||||
- [WeChatVideoDownloader](https://github.com/lecepin/WeChatVideoDownloader) 原项目是react写的,本项目参考原项目用vue3重写了一下,核心逻辑没什么变化,主要是增加了一些新的功能,再次感谢!
|
||||
## 免责声明
|
||||
本软件用于学习研究使用,若因使用本软件造成的一切法律责任均与本人无关!
|
||||
|
||||
2
components.d.ts
vendored
2
components.d.ts
vendored
@@ -15,11 +15,11 @@ declare module 'vue' {
|
||||
ElHeader: typeof import('element-plus/es')['ElHeader']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElLink: typeof import('element-plus/es')['ElLink']
|
||||
ElMain: typeof import('element-plus/es')['ElMain']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElRow: typeof import('element-plus/es')['ElRow']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
Footer: typeof import('./src/components/layout/Footer.vue')['default']
|
||||
|
||||
@@ -3,25 +3,80 @@
|
||||
*/
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/electron-userland/electron-builder/master/packages/app-builder-lib/scheme.json",
|
||||
"appId": "com.putyy.ResDownloader",
|
||||
"appId": "com.putyy.res-downloader",
|
||||
"asar": true,
|
||||
"directories": {
|
||||
"output": "release/${version}"
|
||||
},
|
||||
"files": [
|
||||
"dist-electron",
|
||||
"dist",
|
||||
"electron/res/**/*"
|
||||
"dist"
|
||||
],
|
||||
"mac": {
|
||||
"icon": "electron/res/icon/icons/mac/icon.icns",
|
||||
"artifactName": "${productName}_${version}.${ext}",
|
||||
"icon": "electron/res/icon/mac.icns",
|
||||
"artifactName": "${productName}_${version}.${arch}.${ext}",
|
||||
"singleArchFiles": "*",
|
||||
"target": [
|
||||
"dmg"
|
||||
{
|
||||
"target": "dmg",
|
||||
"arch": [
|
||||
'x64',
|
||||
'arm64',
|
||||
'universal'
|
||||
]
|
||||
}
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "electron/res/darwin/aria2/aria2.conf",
|
||||
"to": "electron/res/darwin/aria2/aria2.conf",
|
||||
"filter": ["**/*"]
|
||||
},
|
||||
{
|
||||
"from": "electron/res/darwin/aria2/${arch}/aria2c",
|
||||
"to": "electron/res/darwin/aria2/aria2c",
|
||||
"filter": ["**/*"],
|
||||
}
|
||||
]
|
||||
},
|
||||
"linux": {
|
||||
"icon": "electron/res/icon/icon.png",
|
||||
"artifactName": "${productName}_${version}.${arch}.${ext}",
|
||||
"category": "Network",
|
||||
"target": [
|
||||
{
|
||||
"target": "AppImage",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64",
|
||||
"armv7l"
|
||||
]
|
||||
},
|
||||
{
|
||||
"target": "deb",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64",
|
||||
"armv7l"
|
||||
]
|
||||
}
|
||||
],
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "electron/res/linux/aria2/aria2.conf",
|
||||
"to": "electron/res/linux/aria2/aria2.conf",
|
||||
"filter": ["**/*"]
|
||||
},
|
||||
{
|
||||
"from": "electron/res/linux/aria2/${arch}/aria2c",
|
||||
"to": "electron/res/linux/aria2/aria2c",
|
||||
"filter": ["**/*"],
|
||||
}
|
||||
]
|
||||
},
|
||||
"win": {
|
||||
"icon": "electron/res/icon/icons/win/icon.ico",
|
||||
"icon": "electron/res/icon/win.ico",
|
||||
"artifactName": "${productName}_${version}.${ext}",
|
||||
"target": [
|
||||
{
|
||||
"target": "nsis",
|
||||
@@ -30,7 +85,13 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"artifactName": "${productName}_${version}.${ext}"
|
||||
"extraResources": [
|
||||
{
|
||||
"from": "electron/res/win",
|
||||
"to": "electron/res/win",
|
||||
"filter": ["**/*"],
|
||||
}
|
||||
]
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
@@ -40,6 +101,7 @@
|
||||
"deleteAppDataOnUninstall": false
|
||||
},
|
||||
"extraResources": [
|
||||
"electron/res"
|
||||
"electron/res/icon",
|
||||
"electron/res/keys",
|
||||
]
|
||||
}
|
||||
|
||||
51
electron/main/aria2Rpc.ts
Normal file
51
electron/main/aria2Rpc.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
const axios = require('axios')
|
||||
import CONFIG from './const'
|
||||
|
||||
export class Aria2RPC {
|
||||
constructor() {
|
||||
this.url = `http://127.0.0.1:${CONFIG.ARIA_PORT}/jsonrpc`
|
||||
this.id = 1
|
||||
}
|
||||
|
||||
call(method, params) {
|
||||
const requestData = {
|
||||
jsonrpc: "2.0",
|
||||
method: method,
|
||||
params: params,
|
||||
id: this.id++
|
||||
};
|
||||
return axios.post(this.url, requestData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
}).then((response)=>{
|
||||
return response.data
|
||||
})
|
||||
}
|
||||
|
||||
addUri(uri, dir, filename, headers = {}) {
|
||||
return this.call('aria2.addUri', [uri, {
|
||||
dir: dir,
|
||||
out: filename,
|
||||
headers: headers,
|
||||
}]);
|
||||
}
|
||||
|
||||
tellStatus(gid) {
|
||||
return this.call('aria2.tellStatus', [gid]);
|
||||
}
|
||||
|
||||
calculateDownloadProgress(bitfield) {
|
||||
// 将十六进制的 bitfield 转换为二进制字符串
|
||||
const totalPieces = bitfield.length * 4; // 每个十六进制字符对应 4 位
|
||||
const binaryString = bitfield.split('').map(hex => parseInt(hex, 16).toString(2).padStart(4, '0')).join('');
|
||||
|
||||
// 计算已下载的部分数
|
||||
const downloadedPieces = binaryString.split('').filter(bit => bit === '1').length;
|
||||
|
||||
// 计算进度百分比
|
||||
const progressPercentage = (downloadedPieces / totalPieces) * 100;
|
||||
|
||||
return progressPercentage.toFixed(2); // 保留两位小数
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,22 @@ export async function installCert(checkInstalled = true) {
|
||||
`echo "输入本地登录密码" && sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${CONFIG.CERT_PUBLIC_PATH}" && touch ${CONFIG.INSTALL_CERT_FLAG} && echo "安装完成"`,
|
||||
)
|
||||
dialog.showMessageBoxSync({
|
||||
type: 'info',
|
||||
type: "info",
|
||||
message: `命令已复制到剪贴板,粘贴命令到终端并运行以安装并信任证书`,
|
||||
});
|
||||
|
||||
reject()
|
||||
});
|
||||
} else if (process.platform === 'linux') {
|
||||
return new Promise((resolve, reject) => {
|
||||
clipboard.writeText(
|
||||
"https://github.com/putyy/res-downloader/blob/master/electron/res/keys/public.pem",
|
||||
)
|
||||
dialog.showMessageBoxSync({
|
||||
type: "info",
|
||||
message: `Linux系统请手动安装证书,已复制下载地址`,
|
||||
});
|
||||
|
||||
reject()
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -13,18 +13,18 @@ const EXECUTABLE_PATH = path.join(
|
||||
)
|
||||
|
||||
const HOME_PATH = path.join(os.homedir(), '.res-downloader@putyy')
|
||||
|
||||
export default {
|
||||
IS_DEV: isDev,
|
||||
EXECUTABLE_PATH,
|
||||
HOME_PATH,
|
||||
APP_CN_NAME: '爱享素材下载器',
|
||||
APP_EN_NAME: 'ResDownloader',
|
||||
CERT_PRIVATE_PATH: path.join(EXECUTABLE_PATH, './keys/private.pem'),
|
||||
CERT_PUBLIC_PATH: path.join(EXECUTABLE_PATH, './keys/public.pem'),
|
||||
INSTALL_CERT_FLAG: path.join(HOME_PATH, './installed.lock'),
|
||||
WIN_CERT_INSTALL_HELPER: path.join(EXECUTABLE_PATH, './w_c.exe'),
|
||||
APP_CN_NAME: '资源下载器',
|
||||
APP_EN_NAME: 'ResDownloader',
|
||||
REGEDIT_VBS_PATH: path.join(EXECUTABLE_PATH, './regedit-vbs'),
|
||||
OPEN_SSL_BIN_PATH: path.join(EXECUTABLE_PATH, './openssl/openssl.exe'),
|
||||
OPEN_SSL_CNF_PATH: path.join(EXECUTABLE_PATH, './openssl/openssl.cnf'),
|
||||
INSTALL_CERT_FLAG: path.join(HOME_PATH, './res-downloader-installed.lock'),
|
||||
WIN_CERT_INSTALL_HELPER: path.join(EXECUTABLE_PATH, './win/w_c.exe'),
|
||||
REGEDIT_VBS_PATH: path.join(EXECUTABLE_PATH, './win/regedit-vbs'),
|
||||
OPEN_SSL_BIN_PATH: path.join(EXECUTABLE_PATH, './win/openssl/openssl.exe'),
|
||||
OPEN_SSL_CNF_PATH: path.join(EXECUTABLE_PATH, './win/openssl/openssl.cnf'),
|
||||
ARIA_PORT: "18899",
|
||||
};
|
||||
|
||||
@@ -3,6 +3,10 @@ import {release} from 'node:os'
|
||||
import {join} from 'node:path'
|
||||
import CONFIG from './const'
|
||||
import initIPC, {setWin} from './ipc'
|
||||
import {closeProxy} from "./setProxy"
|
||||
import log from "electron-log"
|
||||
import path from 'path'
|
||||
import {spawn} from 'child_process'
|
||||
|
||||
// The built directory structure
|
||||
//
|
||||
@@ -45,6 +49,7 @@ process.on('unhandledRejection', () => {
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
let previewWin: BrowserWindow | null = null
|
||||
let aria2Process
|
||||
|
||||
// Here, you can also use other preload
|
||||
const preload = join(__dirname, '../preload/index.js')
|
||||
@@ -77,21 +82,16 @@ app.on('activate', () => {
|
||||
}
|
||||
})
|
||||
|
||||
// New window example arg: new windows url
|
||||
ipcMain.handle('open-win', (_, arg) => {
|
||||
const childWindow = new BrowserWindow({
|
||||
webPreferences: {
|
||||
preload,
|
||||
nodeIntegration: true,
|
||||
contextIsolation: false,
|
||||
},
|
||||
})
|
||||
|
||||
if (process.env.VITE_DEV_SERVER_URL) {
|
||||
childWindow.loadURL(`${url}#${arg}`)
|
||||
} else {
|
||||
childWindow.loadFile(indexHtml, {hash: arg})
|
||||
app.on('before-quit', async e => {
|
||||
e.preventDefault()
|
||||
try {
|
||||
await closeProxy()
|
||||
aria2Process && aria2Process.kill();
|
||||
log.log("--------------closeProxy success--------------")
|
||||
} catch (error) {
|
||||
log.log("--------------proxy catch err--------------", error)
|
||||
}
|
||||
app.exit()
|
||||
})
|
||||
|
||||
function createWindow() {
|
||||
@@ -144,6 +144,8 @@ function createPreviewWindow(parent: BrowserWindow) {
|
||||
parent: parent,
|
||||
width: 600,
|
||||
height: 400,
|
||||
minWidth: 600,
|
||||
minHeight: 400,
|
||||
show: false,
|
||||
// paintWhenInitiallyHidden: false,
|
||||
webPreferences: {
|
||||
@@ -156,11 +158,6 @@ function createPreviewWindow(parent: BrowserWindow) {
|
||||
// previewWin.hide()
|
||||
previewWin.setTitle("预览")
|
||||
|
||||
previewWin.webContents.session.on('will-download', (event, item, webContents) => {
|
||||
// console.log("取消下载")
|
||||
item.cancel()
|
||||
})
|
||||
|
||||
previewWin.on("page-title-updated", (event) => {
|
||||
// 阻止该事件
|
||||
event.preventDefault()
|
||||
@@ -174,9 +171,45 @@ function createPreviewWindow(parent: BrowserWindow) {
|
||||
})
|
||||
}
|
||||
|
||||
function createAria2Process() {
|
||||
// 根据操作系统选择 aria2 的路径
|
||||
try {
|
||||
let aria2Path, aria2Conf
|
||||
if (process.platform === 'win32') {
|
||||
// Windows
|
||||
aria2Path = path.join(CONFIG.EXECUTABLE_PATH, "./win/aria2/aria2c.exe")
|
||||
aria2Conf = path.join(CONFIG.EXECUTABLE_PATH, "./win/aria2/aria2.conf")
|
||||
} else {
|
||||
aria2Path = path.join(CONFIG.EXECUTABLE_PATH, `./${process.platform}/aria2` + (CONFIG.IS_DEV ? `/${process.arch}` : '/') + "/aria2c");
|
||||
aria2Conf = path.join(CONFIG.EXECUTABLE_PATH, `./${process.platform}/aria2/aria2.conf`)
|
||||
}
|
||||
// 启动 aria2
|
||||
console.log("启动 aria2")
|
||||
aria2Process = spawn(aria2Path, [`--conf-path=${aria2Conf}`, `--rpc-listen-port=${CONFIG.ARIA_PORT}`], {
|
||||
windowsHide: false,
|
||||
stdio: CONFIG.IS_DEV ? 'pipe' : 'ignore'
|
||||
});
|
||||
if(!aria2Process){
|
||||
console.log("启动 aria2 失败")
|
||||
}
|
||||
if (CONFIG.IS_DEV) {
|
||||
aria2Process.stdout.on('data', (data) => {
|
||||
console.log(`aria2: ${data}`);
|
||||
});
|
||||
aria2Process.stderr.on('data', (data) => {
|
||||
console.log(`aria2 error: ${data}`);
|
||||
});
|
||||
}
|
||||
console.log("aria2 成功启动")
|
||||
} catch (e) {
|
||||
console.log(`aria2 process start err`, e);
|
||||
}
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
initIPC()
|
||||
createWindow()
|
||||
createPreviewWindow(mainWindow)
|
||||
createAria2Process()
|
||||
setWin(mainWindow, previewWin)
|
||||
})
|
||||
})
|
||||
@@ -1,55 +1,19 @@
|
||||
import {ipcMain, dialog, BrowserWindow, app, shell} from 'electron'
|
||||
import {startServer} from './proxyServer'
|
||||
import {installCert, checkCertInstalled} from './cert'
|
||||
import {downloadFile} from './utils'
|
||||
import {decodeWxFile, typeSuffix, getCurrentDateTimeFormatted} from './utils'
|
||||
// @ts-ignore
|
||||
import {hexMD5} from '../../src/common/md5'
|
||||
import {Aria2RPC} from './aria2Rpc'
|
||||
import fs from "fs"
|
||||
import * as urlTool from "url"
|
||||
import CryptoJS from 'crypto-js'
|
||||
import {closeProxy, setProxy} from "./setProxy"
|
||||
import log from "electron-log"
|
||||
import urlTool from "url";
|
||||
|
||||
let getMac = require("getmac").default
|
||||
let win: BrowserWindow
|
||||
let previewWin: BrowserWindow
|
||||
let isStartProxy = false
|
||||
let isOpenProxy = false
|
||||
let videoList = {}
|
||||
let aesKey = "as5d45as4d6qe6wqfar6gt4749q6y7w6h34v64tv7t37ty5qwtv6t6qv"
|
||||
let qqReg = RegExp("finder.video.qq.com")
|
||||
|
||||
const toSize = (size: number) => {
|
||||
if (size > 1048576) {
|
||||
return (size / 1048576).toFixed(2) + "MB"
|
||||
}
|
||||
if (size > 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB"
|
||||
}
|
||||
return size + 'b'
|
||||
}
|
||||
|
||||
const suffix = (type: string) => {
|
||||
switch (type) {
|
||||
case "video/mp4":
|
||||
return ".mp4";
|
||||
case "image/png":
|
||||
return ".png";
|
||||
case "image/webp":
|
||||
return ".webp";
|
||||
case "image/svg+xml":
|
||||
return ".svg";
|
||||
case "image/gif":
|
||||
return ".gif";
|
||||
case "audio/mpeg":
|
||||
return ".mp3";
|
||||
case "application/vnd.apple.mpegurl":
|
||||
return ".m3u8";
|
||||
}
|
||||
}
|
||||
const aria2RpcClient = new Aria2RPC()
|
||||
|
||||
export default function initIPC() {
|
||||
|
||||
ipcMain.handle('invoke_app_is_init', async (event, arg) => {
|
||||
// 初始化应用 安装证书相关
|
||||
return checkCertInstalled()
|
||||
@@ -57,132 +21,23 @@ export default function initIPC() {
|
||||
|
||||
ipcMain.handle('invoke_init_app', (event, arg) => {
|
||||
// 开始 初始化应用 安装证书相关
|
||||
// console.log('invoke_init_app')
|
||||
return installCert(false)
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_start_proxy', async (event, arg) => {
|
||||
// 启动代理服务
|
||||
if (isStartProxy) {
|
||||
if (isOpenProxy === false) {
|
||||
isOpenProxy = true
|
||||
setProxy('127.0.0.1', 8899)
|
||||
.then(() => {
|
||||
})
|
||||
.catch((err) => {
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
isStartProxy = true
|
||||
isOpenProxy = true
|
||||
return startServer({
|
||||
// @ts-ignore
|
||||
interceptCallback: phase => async (req, res) => {
|
||||
// 拦截响应
|
||||
if (phase === 'response') {
|
||||
let ctype = res?._data?.headers?.['content-type']
|
||||
let url_sign: string = hexMD5(req.fullUrl())
|
||||
let res_url = req.fullUrl()
|
||||
let urlInfo = urlTool.parse(res_url, true)
|
||||
switch (ctype) {
|
||||
case "video/mp4":
|
||||
if (videoList.hasOwnProperty(url_sign) === false) {
|
||||
videoList[url_sign] = req.fullUrl()
|
||||
let high_url = ''
|
||||
let down_url = res_url
|
||||
if (qqReg.test(down_url)) {
|
||||
down_url = down_url.replace("finder.video.qq.com/251/20302", "finder.video.qq.com/251/20304")
|
||||
urlInfo = urlTool.parse(down_url, true)
|
||||
high_url = urlInfo.protocol + "//" + urlInfo.hostname + urlInfo.pathname
|
||||
+ '?encfilekey=' + urlInfo.query?.encfilekey
|
||||
+ '&token=' + urlInfo.query?.token
|
||||
}
|
||||
|
||||
win?.webContents?.send?.('on_get_queue', {
|
||||
url_sign: url_sign,
|
||||
url: down_url,
|
||||
down_url: down_url,
|
||||
high_url: high_url,
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(res?._data?.headers?.['content-length'] ?? 0),
|
||||
type: ctype,
|
||||
type_str: 'video',
|
||||
progress_bar: '',
|
||||
save_path: '',
|
||||
downing: false
|
||||
})
|
||||
}
|
||||
break;
|
||||
case "image/png":
|
||||
case "image/webp":
|
||||
case "image/svg+xml":
|
||||
case "image/gif":
|
||||
win?.webContents?.send?.('on_get_queue', {
|
||||
url_sign: url_sign,
|
||||
url: res_url,
|
||||
down_url: res_url,
|
||||
high_url: '',
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(res?._data?.headers?.['content-length'] ?? 0),
|
||||
type: ctype,
|
||||
type_str: 'image',
|
||||
progress_bar: '',
|
||||
save_path: '',
|
||||
downing: false
|
||||
})
|
||||
break;
|
||||
case "audio/mpeg":
|
||||
win?.webContents?.send?.('on_get_queue', {
|
||||
url_sign: url_sign,
|
||||
url: res_url,
|
||||
down_url: res_url,
|
||||
high_url: '',
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(res?._data?.headers?.['content-length'] ?? 0),
|
||||
type: ctype,
|
||||
type_str: 'audio',
|
||||
progress_bar: '',
|
||||
save_path: '',
|
||||
downing: false
|
||||
})
|
||||
break;
|
||||
case "application/vnd.apple.mpegurl":
|
||||
win?.webContents?.send?.('on_get_queue', {
|
||||
url_sign: url_sign,
|
||||
url: res_url,
|
||||
down_url: res_url,
|
||||
high_url: '',
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(res?._data?.headers?.['content-length'] ?? 0),
|
||||
type: ctype,
|
||||
type_str: 'm3u8',
|
||||
progress_bar: '',
|
||||
save_path: '',
|
||||
downing: false
|
||||
})
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
setProxyErrorCallback: err => {
|
||||
isStartProxy = false
|
||||
isOpenProxy = false
|
||||
},
|
||||
installCert(false).then(r => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_close_proxy', (event, arg) => {
|
||||
// 关闭代理
|
||||
try {
|
||||
isOpenProxy = false
|
||||
return closeProxy()
|
||||
} catch (error) {
|
||||
log.log("--------------closeProxy error--------------", error)
|
||||
ipcMain.handle('invoke_start_proxy', (event, arg) => {
|
||||
// 启动代理服务
|
||||
if (isStartProxy) {
|
||||
return
|
||||
}
|
||||
|
||||
isStartProxy = true
|
||||
return startServer({
|
||||
win: win,
|
||||
upstreamProxy: arg.upstream_proxy ? arg.upstream_proxy : "",
|
||||
setProxyErrorCallback: err => {
|
||||
console.log('setProxyErrorCallback', err)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_select_down_dir', async (event, arg) => {
|
||||
@@ -195,50 +50,102 @@ export default function initIPC() {
|
||||
return result?.[0]
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_file_exists', async (event, {save_path, url}) => {
|
||||
let url_sign = hexMD5(url)
|
||||
let res = fs.existsSync(`${save_path}/${url_sign}.mp4`)
|
||||
return {is_file: res, fileName: `${save_path}/${url_sign}.mp4`}
|
||||
ipcMain.handle('invoke_select_wx_file', async (event, {index, data}) => {
|
||||
// 选择下载位置
|
||||
const result = dialog.showOpenDialogSync({title: '保存', properties: ['openFile']})
|
||||
if (!result?.[0]) {
|
||||
return false
|
||||
}
|
||||
return decodeWxFile(result?.[0], data.decode_key, result?.[0].replace(".mp4", "_解密.mp4"))
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_down_file', async (event, {index, data, save_path, high}) => {
|
||||
let down_url = data.down_url
|
||||
if (high && data.high_url) {
|
||||
down_url = data.high_url
|
||||
}
|
||||
ipcMain.handle('invoke_file_exists', async (event, {save_path, url, description}) => {
|
||||
let fileName = description ? description.replace(/[^a-zA-Z\u4e00-\u9fa5]/g, '') : hexMD5(url);
|
||||
let res = fs.existsSync(`${save_path}/${fileName}.mp4`)
|
||||
return {is_file: res, fileName: `${save_path}/${fileName}.mp4`}
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_down_file', async (event, {data, save_path, quality}) => {
|
||||
let down_url = data.url
|
||||
if (!down_url) {
|
||||
return false
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve(false);
|
||||
});
|
||||
}
|
||||
|
||||
let url_sign = hexMD5(down_url)
|
||||
let save_path_file = `${save_path}/${url_sign}` + suffix(data.type)
|
||||
if (fs.existsSync(save_path_file)) {
|
||||
return {fullFileName: save_path_file, totalLen: ""}
|
||||
}
|
||||
// 开始下载
|
||||
return downloadFile(
|
||||
down_url,
|
||||
save_path_file,
|
||||
(res) => {
|
||||
return save_path_file
|
||||
if(quality === "0" && data.decode_key){
|
||||
const urlInfo = urlTool.parse(down_url, true);
|
||||
console.log('urlInfo', urlInfo)
|
||||
if (urlInfo.query["token"] && urlInfo.query["encfilekey"]) {
|
||||
down_url = urlInfo.protocol + "//" + urlInfo.hostname + urlInfo.pathname.replace("251/20302", "251/20304") +
|
||||
"?encfilekey=" + urlInfo.query["encfilekey"] +
|
||||
"&token=" + urlInfo.query["token"]
|
||||
console.log("down_url:", down_url)
|
||||
}
|
||||
).catch(err => {
|
||||
// console.log('invoke_down_file:err', err)
|
||||
return false
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_get_mac', async (event) => {
|
||||
let mac = getMac()
|
||||
if (mac === "") {
|
||||
return ""
|
||||
} else if (quality !== "-1" && data.decode_key && data.file_format) {
|
||||
const format = data.file_format.split('#');
|
||||
const qualityMap = [
|
||||
format[0],
|
||||
format[Math.floor(format.length / 2)],
|
||||
format[format.length - 1]
|
||||
];
|
||||
down_url += "&X-snsvideoflag=" + qualityMap[quality];
|
||||
}
|
||||
return CryptoJS.AES.encrypt(mac, CryptoJS.enc.Hex.parse(aesKey), {
|
||||
mode: CryptoJS.mode.ECB,
|
||||
padding: CryptoJS.pad.Pkcs7
|
||||
}).ciphertext.toString()
|
||||
})
|
||||
let fileName = data?.description ? data.description.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '') : hexMD5(down_url);
|
||||
fileName = fileName + "_" + getCurrentDateTimeFormatted() + typeSuffix(data.type)[1]
|
||||
let save_path_file = `${save_path}/${fileName}`
|
||||
if (process.platform === 'win32') {
|
||||
save_path_file = `${save_path}\\${fileName}`
|
||||
}
|
||||
|
||||
let headers = {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
if (down_url.includes("douyin")) {
|
||||
headers['Referer'] = down_url
|
||||
}
|
||||
|
||||
aria2RpcClient.addUri([down_url], save_path, fileName, headers).then((response) => {
|
||||
let currentGid = response.result // 保存当前下载的 gid
|
||||
let progressIntervalId = null
|
||||
// // 开始定时查询下载进度
|
||||
progressIntervalId = setInterval(() => {
|
||||
aria2RpcClient.tellStatus(currentGid).then((status) => {
|
||||
if (status.result.status !== "complete") {
|
||||
const progress = aria2RpcClient.calculateDownloadProgress(status.result.bitfield);
|
||||
win?.webContents.send('on_down_file_schedule', {schedule: `已下载${progress}%`})
|
||||
} else {
|
||||
clearInterval(progressIntervalId);
|
||||
if (data.decode_key) {
|
||||
win?.webContents.send('on_down_file_schedule', {schedule: `开始解密`})
|
||||
decodeWxFile(save_path_file, data.decode_key, save_path_file.replace(".mp4", "_wx.mp4")).then((res) => {
|
||||
fs.unlink(save_path_file, (err) => {
|
||||
})
|
||||
resolve(res);
|
||||
}).catch((error) => {
|
||||
console.log("err:", error)
|
||||
resolve(false);
|
||||
});
|
||||
} else {
|
||||
resolve({
|
||||
fullFileName: save_path_file,
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.error(error);
|
||||
clearInterval(progressIntervalId);
|
||||
resolve(false);
|
||||
});
|
||||
}, 1000);
|
||||
}).catch((error) => {
|
||||
console.log("err:", error)
|
||||
resolve(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.handle('invoke_resources_preview', async (event, {url}) => {
|
||||
if (!url) {
|
||||
@@ -254,15 +161,32 @@ export default function initIPC() {
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_open_default_browser', (event, {url}) => {
|
||||
shell.openExternal(url).then(r => {})
|
||||
shell.openExternal(url).then(r => {
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_open_dir', (event, {dir}) => {
|
||||
shell.openPath(dir).then(r => {})
|
||||
ipcMain.handle('invoke_open_file_dir', (event, {save_path}) => {
|
||||
shell.showItemInFolder(save_path)
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_file_del', (event, {url_sign}) => {
|
||||
if (url_sign === "all") {
|
||||
global.videoList = {}
|
||||
return
|
||||
}
|
||||
if (url_sign) {
|
||||
delete global.videoList[url_sign]
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_window_restart', (event) => {
|
||||
app.relaunch()
|
||||
app.exit()
|
||||
})
|
||||
}
|
||||
|
||||
export function setWin(w, p) {
|
||||
win = w
|
||||
previewWin = p
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +1,177 @@
|
||||
import fs from 'fs'
|
||||
import log from 'electron-log'
|
||||
import CONFIG from './const'
|
||||
import {closeProxy, setProxy} from './setProxy'
|
||||
import {app} from "electron"
|
||||
import {setProxy} from './setProxy'
|
||||
import * as urlTool from "url"
|
||||
import {toSize, typeSuffix} from "./utils"
|
||||
// @ts-ignore
|
||||
import {hexMD5} from '../../src/common/md5'
|
||||
import pkg from '../../package.json'
|
||||
|
||||
const hoXy = require('hoxy')
|
||||
|
||||
const port = 8899
|
||||
|
||||
global.videoList = {}
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
process.env.OPENSSL_BIN = CONFIG.OPEN_SSL_BIN_PATH
|
||||
process.env.OPENSSL_CONF = CONFIG.OPEN_SSL_CNF_PATH
|
||||
}
|
||||
|
||||
export async function startServer({
|
||||
interceptCallback = f => f => f,
|
||||
setProxyErrorCallback = f => f,
|
||||
}) {
|
||||
// const port = await getPort()
|
||||
const port = 8899
|
||||
const resObject = {
|
||||
url: "",
|
||||
url_sign: "",
|
||||
cover_url: "",
|
||||
file_format: "",
|
||||
platform: "",
|
||||
size: "",
|
||||
type: "video/mp4",
|
||||
type_str: 'video',
|
||||
progress_bar: "",
|
||||
save_path: "",
|
||||
decode_key: "",
|
||||
description: ""
|
||||
}
|
||||
|
||||
const vv = hexMD5(pkg.version) + (CONFIG.IS_DEV ? Math.random() :"")
|
||||
|
||||
export async function startServer({win, upstreamProxy, setProxyErrorCallback = f => f,}) {
|
||||
return new Promise(async (resolve: any, reject) => {
|
||||
const proxy = hoXy
|
||||
.createServer({
|
||||
try {
|
||||
const proxy = hoXy.createServer({
|
||||
upstreamProxy: upstreamProxy,
|
||||
certAuthority: {
|
||||
key: fs.readFileSync(CONFIG.CERT_PRIVATE_PATH),
|
||||
cert: fs.readFileSync(CONFIG.CERT_PUBLIC_PATH),
|
||||
},
|
||||
})
|
||||
.listen(port, () => {
|
||||
setProxy('127.0.0.1', port)
|
||||
.then(() => {
|
||||
log.log("--------------setProxy success--------------")
|
||||
resolve()
|
||||
})
|
||||
.catch((err) => {
|
||||
log.log("--------------setProxy error--------------")
|
||||
// setProxyErrorCallback(data);
|
||||
setProxyErrorCallback({});
|
||||
reject('设置代理失败');
|
||||
});
|
||||
})
|
||||
.on('error', err => {
|
||||
log.log("--------------proxy err--------------", err)
|
||||
});
|
||||
.listen(port, () => {
|
||||
setProxy('127.0.0.1', port)
|
||||
.then((res) => {
|
||||
resolve()
|
||||
})
|
||||
.catch((err) => {
|
||||
setProxyErrorCallback(err)
|
||||
reject('setting proxy err: ' + err.toString())
|
||||
});
|
||||
})
|
||||
.on('error', err => {
|
||||
setProxyErrorCallback(err)
|
||||
reject('proxy service err: ' + err.toString())
|
||||
})
|
||||
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'request',
|
||||
},
|
||||
interceptCallback('request'),
|
||||
);
|
||||
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'response',
|
||||
},
|
||||
interceptCallback('response'),
|
||||
)
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'request',
|
||||
hostname: 'res-downloader.666666.com',
|
||||
as: 'json',
|
||||
},
|
||||
(req, res) => {
|
||||
res.string = 'ok'
|
||||
res.statusCode = 200
|
||||
try {
|
||||
if (req.json?.media?.length <= 0) {
|
||||
return
|
||||
}
|
||||
const media = req.json?.media[0]
|
||||
const url_sign: string = hexMD5(media.url)
|
||||
if (!media?.decodeKey || global.videoList.hasOwnProperty(url_sign) === true) {
|
||||
return
|
||||
}
|
||||
const urlInfo = urlTool.parse(media.url, true)
|
||||
global.videoList[url_sign] = media.url
|
||||
win.webContents.send('on_get_queue', Object.assign({}, resObject, {
|
||||
url_sign: url_sign,
|
||||
url: media.url + media.urlToken,
|
||||
cover_url: media.coverUrl,
|
||||
file_format: media.spec.map((res)=> res.fileFormat).join('#'),
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(media.fileSize),
|
||||
type: "video/mp4",
|
||||
type_str: 'video',
|
||||
decode_key: media.decodeKey,
|
||||
description: req.json.description,
|
||||
}))
|
||||
} catch (e) {
|
||||
log.log(e.toString())
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'response',
|
||||
hostname: 'channels.weixin.qq.com',
|
||||
as: 'string',
|
||||
},
|
||||
async (req, res) => {
|
||||
if (req.url.includes('/web/pages/feed') || req.url.includes('/web/pages/home')) {
|
||||
res.string = res.string.replaceAll('.js"', '.js?v=' + vv + '"')
|
||||
res.statusCode = 200
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'response',
|
||||
hostname: 'res.wx.qq.com',
|
||||
as: 'string',
|
||||
},
|
||||
async (req, res) => {
|
||||
if (req.url.endsWith('.js?v=' + vv)) {
|
||||
res.string = res.string.replaceAll('.js"', '.js?v=' + vv + '"');
|
||||
}
|
||||
if (req.url.includes("web/web-finder/res/js/virtual_svg-icons-register.publish")) {
|
||||
res.string = res.string.replace(/get\s*media\s*\(\)\s*\{/, `
|
||||
get media(){
|
||||
if(this.objectDesc){
|
||||
fetch("https://res-downloader.666666.com", {
|
||||
method: "POST",
|
||||
mode: "no-cors",
|
||||
body: JSON.stringify(this.objectDesc),
|
||||
});
|
||||
};
|
||||
`)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
proxy.intercept(
|
||||
{
|
||||
phase: 'response',
|
||||
},
|
||||
async (req, res) => {
|
||||
try {
|
||||
// 拦截响应
|
||||
const contentType = res?._data?.headers?.['content-type']
|
||||
const [resType, suffix] = typeSuffix(contentType)
|
||||
if (resType) {
|
||||
const url_sign: string = hexMD5(req.fullUrl())
|
||||
const res_url = req.fullUrl()
|
||||
const urlInfo = urlTool.parse(res_url, true)
|
||||
const contentLength = res?._data?.headers?.['content-length']
|
||||
if (global.videoList.hasOwnProperty(url_sign) === false) {
|
||||
global.videoList[url_sign] = res_url
|
||||
win.webContents.send('on_get_queue', Object.assign({}, resObject, {
|
||||
url: res_url,
|
||||
url_sign: url_sign,
|
||||
platform: urlInfo.hostname,
|
||||
size: toSize(contentLength ? contentLength : 0),
|
||||
type: contentType,
|
||||
type_str: resType,
|
||||
}))
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log.log(e.toString())
|
||||
}
|
||||
},
|
||||
)
|
||||
} catch (e) {
|
||||
log.log("--------------proxy catch err--------------", e)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
app.on('before-quit', async e => {
|
||||
e.preventDefault()
|
||||
try {
|
||||
await closeProxy()
|
||||
log.log("--------------closeProxy success--------------")
|
||||
} catch (error) {
|
||||
}
|
||||
app.exit()
|
||||
})
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import {exec} from 'child_process'
|
||||
// @ts-ignore
|
||||
import regedit from 'regedit'
|
||||
import CONFIG from './const'
|
||||
import {dialog} from "electron";
|
||||
|
||||
regedit.setExternalVBSLocation(CONFIG.REGEDIT_VBS_PATH)
|
||||
|
||||
@@ -22,12 +23,24 @@ export async function setProxy(host, port) {
|
||||
if (error) {
|
||||
reject(null)
|
||||
} else {
|
||||
resolve(network)
|
||||
exec(`networksetup -setwebproxy "${network}" ${host} ${port}`, error => {
|
||||
if (error) {
|
||||
reject(null)
|
||||
} else {
|
||||
resolve(network)
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}),
|
||||
);
|
||||
} else if (process.platform === 'linux') {
|
||||
dialog.showMessageBoxSync({
|
||||
type: "info",
|
||||
message: `请手动设置系统代理`,
|
||||
});
|
||||
return new Promise((resolve, reject) => {})
|
||||
} else {
|
||||
const valuesToPut = {
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings': {
|
||||
@@ -63,12 +76,23 @@ export async function closeProxy() {
|
||||
if (error) {
|
||||
reject(null)
|
||||
} else {
|
||||
resolve(network)
|
||||
exec(`networksetup -setwebproxystate "${network}" off`, error => {
|
||||
if (error) {
|
||||
reject(null)
|
||||
} else {
|
||||
resolve(network)
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}),
|
||||
);
|
||||
} else if (process.platform === 'linux') {
|
||||
dialog.showMessageBoxSync({
|
||||
type: "info",
|
||||
message: `请手动取消系统代理`,
|
||||
});
|
||||
} else {
|
||||
const valuesToPut = {
|
||||
'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings': {
|
||||
@@ -113,4 +137,4 @@ function getMacAvailableNetworks() {
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,43 @@
|
||||
import fs from 'fs'
|
||||
import {Transform} from 'stream'
|
||||
import {getDecryptionArray} from '../wxjs/decrypt.js'
|
||||
|
||||
const axios = require('axios')
|
||||
|
||||
function downloadFile(url, fullFileName, progressCallback) {
|
||||
return axios.get(url, {
|
||||
function xorTransform(decryptionArray) {
|
||||
let processedBytes = 0;
|
||||
return new Transform({
|
||||
transform(chunk, encoding, callback) {
|
||||
if (processedBytes < decryptionArray.length) {
|
||||
let remaining = Math.min(decryptionArray.length - processedBytes, chunk.length);
|
||||
for (let i = 0; i < remaining; i++) {
|
||||
chunk[i] = chunk[i] ^ decryptionArray[processedBytes + i];
|
||||
}
|
||||
processedBytes += remaining;
|
||||
}
|
||||
this.push(chunk);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function downloadFile(url, decodeKey, fullFileName, progressCallback) {
|
||||
let xorStream = null
|
||||
if (decodeKey) {
|
||||
xorStream = xorTransform(getDecryptionArray(decodeKey));
|
||||
}
|
||||
let config = {
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36',
|
||||
},
|
||||
}).then(({data, headers}) => {
|
||||
}
|
||||
|
||||
if (url.includes("douyin")) {
|
||||
config.headers['Referer'] = url
|
||||
}
|
||||
|
||||
return axios.get(url, config).then(({data, headers}) => {
|
||||
let currentLen = 0
|
||||
const totalLen = headers['content-length']
|
||||
|
||||
@@ -20,17 +49,126 @@ function downloadFile(url, fullFileName, progressCallback) {
|
||||
});
|
||||
|
||||
data.on('error', err => reject(err))
|
||||
|
||||
data.pipe(
|
||||
fs.createWriteStream(fullFileName).on('finish', () => {
|
||||
resolve({
|
||||
fullFileName,
|
||||
totalLen,
|
||||
});
|
||||
}),
|
||||
);
|
||||
if (xorStream) {
|
||||
data.pipe(xorStream).pipe(
|
||||
fs.createWriteStream(fullFileName).on('finish', () => {
|
||||
resolve({
|
||||
fullFileName,
|
||||
totalLen,
|
||||
});
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
data.pipe(
|
||||
fs.createWriteStream(fullFileName).on('finish', () => {
|
||||
resolve({
|
||||
fullFileName,
|
||||
totalLen,
|
||||
});
|
||||
}),
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export {downloadFile}
|
||||
function decodeWxFile(fileName, decodeKey, fullFileName) {
|
||||
let xorStream = xorTransform(getDecryptionArray(decodeKey));
|
||||
let data = fs.createReadStream(fileName);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
data.on('error', err => reject(err));
|
||||
data.pipe(xorStream).pipe(
|
||||
fs.createWriteStream(fullFileName).on('finish', () => {
|
||||
resolve({
|
||||
fullFileName,
|
||||
});
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function toSize(size: number) {
|
||||
if (size > 1048576) {
|
||||
return (size / 1048576).toFixed(2) + "MB"
|
||||
}
|
||||
if (size > 1024) {
|
||||
return (size / 1024).toFixed(2) + "KB"
|
||||
}
|
||||
return size + 'b'
|
||||
}
|
||||
|
||||
function typeSuffix(type: string) {
|
||||
switch (type) {
|
||||
case "video/mp4":
|
||||
case "video/webm":
|
||||
case "video/ogg":
|
||||
case "video/x-msvideo":
|
||||
case "video/mpeg":
|
||||
case "video/quicktime":
|
||||
case "video/x-ms-wmv":
|
||||
case "video/3gpp":
|
||||
case "video/x-matroska":
|
||||
return ["video", ".mp4"];
|
||||
case "audio/video":
|
||||
case "video/x-flv":
|
||||
return ["live", ".mp4"];
|
||||
case "image/png":
|
||||
case "image/webp":
|
||||
case "image/jpeg":
|
||||
case "image/jpg":
|
||||
case "image/gif":
|
||||
case "image/avif":
|
||||
case "image/bmp":
|
||||
case "image/tiff":
|
||||
case "image/heic":
|
||||
case "image/x-icon":
|
||||
case "image/svg+xml":
|
||||
case "image/vnd.adobe.photoshop":
|
||||
return ["image", ".png"];
|
||||
case "audio/mpeg":
|
||||
case "audio/wav":
|
||||
case "audio/aiff":
|
||||
case "audio/x-aiff":
|
||||
case "audio/aac":
|
||||
case "audio/ogg":
|
||||
case "audio/flac":
|
||||
case "audio/midi":
|
||||
case "audio/x-midi":
|
||||
case "audio/x-ms-wma":
|
||||
case "audio/opus":
|
||||
case "audio/webm":
|
||||
case "audio/mp4":
|
||||
return ["audio", ".mp3"];
|
||||
case "application/vnd.apple.mpegurl":
|
||||
case "application/x-mpegURL":
|
||||
return ["m3u8", ".m3u8"];
|
||||
case "application/pdf":
|
||||
return ["pdf", ".pdf"];
|
||||
case "application/vnd.ms-powerpoint":
|
||||
case "application/vnd.openxmlformats-officedocument.presentationml.presentation":
|
||||
return ["ppt", ".ppt"];
|
||||
case "application/vnd.ms-excel":
|
||||
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
||||
return ["xls", ".xls"];
|
||||
case "application/msword":
|
||||
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
||||
return ["doc", ".doc"];
|
||||
}
|
||||
return ["", ""]
|
||||
}
|
||||
|
||||
function getCurrentDateTimeFormatted() {
|
||||
const now = new Date();
|
||||
|
||||
const year = now.getFullYear();
|
||||
const month = String(now.getMonth() + 1).padStart(2, '0'); // 月份从0开始,所以要加1
|
||||
const day = String(now.getDate()).padStart(2, '0');
|
||||
const hours = String(now.getHours()).padStart(2, '0');
|
||||
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||
const seconds = String(now.getSeconds()).padStart(2, '0');
|
||||
|
||||
return `${year}${month}${day}${hours}${minutes}${seconds}`;
|
||||
}
|
||||
|
||||
export {downloadFile, toSize, decodeWxFile, typeSuffix, getCurrentDateTimeFormatted}
|
||||
|
||||
@@ -25,12 +25,6 @@ const safeDOM = {
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* https://tobiasahlin.com/spinkit
|
||||
* https://connoratherton.com/loaders
|
||||
* https://projects.lukehaas.me/css-loaders
|
||||
* https://matejkustec.github.io/SpinThatShit
|
||||
*/
|
||||
function useLoading() {
|
||||
const className = `loaders-css__square-spin`
|
||||
const styleContent = `
|
||||
|
||||
25
electron/res/darwin/aria2/aria2.conf
Normal file
25
electron/res/darwin/aria2/aria2.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
#允许rpc
|
||||
enable-rpc=true
|
||||
#允许非外部访问
|
||||
rpc-listen-all=true
|
||||
|
||||
#最大同时下载数(任务数), 路由建议值: 3
|
||||
max-concurrent-downloads=3
|
||||
#断点续传
|
||||
continue=true
|
||||
#同服务器连接数
|
||||
max-connection-per-server=10
|
||||
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
|
||||
min-split-size=10M
|
||||
#单文件最大线程数, 路由建议值: 5
|
||||
split=10
|
||||
#下载速度限制
|
||||
max-overall-download-limit=0
|
||||
#单文件速度限制
|
||||
max-download-limit=0
|
||||
#上传速度限制
|
||||
max-overall-upload-limit=0
|
||||
#单文件速度限制
|
||||
max-upload-limit=0
|
||||
|
||||
check-certificate=false
|
||||
BIN
electron/res/darwin/aria2/arm64/aria2c
Executable file
BIN
electron/res/darwin/aria2/arm64/aria2c
Executable file
Binary file not shown.
BIN
electron/res/darwin/aria2/x64/aria2c
Executable file
BIN
electron/res/darwin/aria2/x64/aria2c
Executable file
Binary file not shown.
0
electron/res/icon/icons/mac/icon.icns → electron/res/icon/mac.icns
Executable file → Normal file
0
electron/res/icon/icons/mac/icon.icns → electron/res/icon/mac.icns
Executable file → Normal file
0
electron/res/icon/icons/win/icon.ico → electron/res/icon/win.ico
Executable file → Normal file
0
electron/res/icon/icons/win/icon.ico → electron/res/icon/win.ico
Executable file → Normal file
|
Before Width: | Height: | Size: 199 KiB After Width: | Height: | Size: 199 KiB |
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>资源下载器</title>
|
||||
<title>爱享素材下载器</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAsmAqn3hYd/YZcrfgqM1Q6xgHI50EBckbOkfCqTWS1yVFZjLF
|
||||
bMehWb9xGFZJD21A5sxl4xelIWblhety+YTVa/mn2CEJh3je069oeULfXdzhhHyf
|
||||
/ci0IloJhvX+2RJ+176uTKKcWhuOtNVs5VeFoHDoUcISnTqkaVyWeeLfafgrOW7w
|
||||
N8ip128nuBx19ylIygb/DELmjKRRCSpx2vOw2JErTM8L5r0f4eWdqiwBOwu0NHWy
|
||||
Svh9YG8B31UPga4I8FbFhybOP9cQNQPafOSfjwuZoi5CAtyJbwT7KyII9iMD74bZ
|
||||
1mTx2xokmQ2TeiCSKSF8Mx9/8Gq+95mzvvIbRwIDAQABAoIBAHNt++caj9WBclJk
|
||||
X4Oc6eJYuDX5o+LCk1YRngy12IJVYiWScWPFg8p6MouXOsw63Sb92mksofWNirYw
|
||||
+UQzC5FGC7G3H12FgFzoQ+lEtxscluuPYlFukfMw5L1rbzG14FNo145MJHXDI4Qu
|
||||
ILwA+T4sEorl1fndOwvbmJzjjcQaeRNz7/R9e6QTOlZ2+IEMKnHSBXXGJbDj6mPN
|
||||
+f1/ec6nVENdxazgRCi0xfinyft4Ipst93Eb+wGcpk+J43aF+0leWQCdl6Y9U1Lz
|
||||
zpv5H5XOQdwpX+dpuioRp73zwPwIialq+hTUN28Bn9U1jW2tjxUl/vgIpjy1s94a
|
||||
UipRwSECgYEA57vYB+wGnxQxY9IPpr9H/y3HciIwCnuOEsWBzjYe8sIqBif2tEpO
|
||||
OgDZZMQY7+JJrDQbDRs442TuRjKhJ5hiW+MyoiFWaYkBBoNVM8RBTkIjHfrh+uB2
|
||||
XT15FbEyyxo3n9QY610ZJFRnW4Uf5V0osjOqqUgQRrVXvamk6NQH6FkCgYEAxQ3v
|
||||
jFYPL3EkZe1br6X0RM42ykGv5Di5Q6NnjpSPcyn9a2obA1cZuCd5S1lhrkuZGsdI
|
||||
iFapeL+7vpts9gu9/ii9y+CgEKplOMmm0ZrChBKAcXMZvdDKV3y5SmTMZPas4X5i
|
||||
hqNqatx9/J93sMYWc0CuoosDEJYKtSz8GE+1rJ8CgYAmp5rdl21zU7b5Y6zgr7+e
|
||||
vVArpbBFz15fmzqP309CR0kjRb9NS6fI3SNmP5+5RBHt+7MXeJcAt3FXnFJtfGnL
|
||||
0hY8HTuA1y2onHe17uLF3xpkgdj4NEEKRJrSF4DViEYHDyYo/JqZCMtE5OvxIp0L
|
||||
PLsXCcJNSSqdpJKxk8zN4QKBgEuoxSAh7uStUWddUkXHt1kvwDO6MtmyuddxhxJk
|
||||
kguKxMWYUNTgfXyKk3TN1caBOkDg4UWP2LQHEgPmU1jJO2K5q9362hpsAj9ilY2H
|
||||
GUZygCSPKAQMhZQ/zDj3KM9fMxPFXfkKB5MOI8V6SQ9zjy0jWaoJK90TbvsPUZ/Y
|
||||
Aw5LAoGADifZwCHPiXhTfJjOom2uBgXmL03yTXcCw4EDIX3ZR0sP6ACPQq4T4jxZ
|
||||
UJLXLjOb2pzCq0c5+k0cG6ahYINq4tGOo+vQ9fDvhKg0nlf1FrzxSd7S12o+un2q
|
||||
+U+dBllYIDlRMgMhXu9CxFDjUsCwPRmsBvmVZiH4XSs6QVnfn90=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG
|
||||
/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ
|
||||
H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS
|
||||
KY8SXZVY315daqz2eRWsm2otqjqbWGhh9c7FGHr3r9aAG08dyaO6OvK14GJIhNV+
|
||||
UOPH5hDMMaxurDt8znaSUw93b7D++aEninGro/s2LY4G91dgM8i4t88UWobXpqs5
|
||||
GMGTI0InLX2I66HkteH4RRfXXC9svA2CxN3yP294FIP7gdRQ1CGJeJcluzsjtx0V
|
||||
i2G9vrT1AgMBAAECggEAF0obfQ4a82183qqHC0iui+tOpOvPeyl3G0bLDPx09wIC
|
||||
2iITV//xF2GgGzE8q0wmEd2leMZ+GFn3BrYh6kPfUfxbz+RfxMtTCDZB34xt6YzT
|
||||
MG1op9ft+DQUa7WZ6r7NCQJwGzllRqqZncp4MeFlpPo+6nQXyh4WhSYNnredbENE
|
||||
uPZ63Kme4RZfMvtVso+XgAQM3oDih0onv1YitmNQpL9rRzlthTfybAT4737DBINq
|
||||
zsmBNE6QIsXnSKpzo11OtDgof2QM9ac6eAXf73oTpDxfodwCotILytKn+8WYvlR+
|
||||
T15uuknb4M3XI1FPVolkF4qtK5SLAAbVzV4DsCmuIQKBgQD6bTKKbL2huvU6dEKx
|
||||
bgS079LfQUxxOTClgwkhVsMxRtvcPBnHYMAsPK4mnMhEh9x+TF6wxMx0pmhQluPI
|
||||
ZULNBj/qdoiBL0RwVLA+9jgE0NeWB3XXFDsEavQBr9Q8CC0uzrsgsxFcvHpqqs2Q
|
||||
RtngxRWtJP06D6mKC23s4YjDHwKBgQDg9KUCFqOmWcRXyeg9gYMC4jFFQw4lUQBd
|
||||
sYpqSMHDw1b+T1W/dCPbwbxZL/+d8y930BYy9QYDtQwHdLyXCH0pHM7S6rfgr5xk
|
||||
2Szd8xBUIqmeV/zcR00mTeQHJ1M50VHfclAVgZgkpWSoLwbX+bXyx/mfqLAtynZ5
|
||||
yU9RfrT5awKBgQC0uJ8TlFvZXjFgyMvkfY/5/2R/ZwFCaFI573FkVNeyNP+vVNQJ
|
||||
tUGZ6wSGqvg/tIgjwPtIuA0QVZLMLcgeMy1dBhiUHIxwJetO4V77YPaWSxx5kdKx
|
||||
r1DT5FdI7FnOJNxufhQ/CdsKwJ3bYn3Mk8TiV3hIJnx0LR9dltfybeQjYwKBgDOY
|
||||
6aApATBOtrJMJXC2HA61QwfX8Y6tnZ/f8RefyJHWZEXAfLKFORRWw5TRZZgdB247
|
||||
1Furx81h4Xh0Vi1uTQb5DJdkLvjiTsTy60+dSMmDidQ/6ke8Mv3uL7dUVcqVMGpI
|
||||
FgZYy0TcitHot3EiXZFqPN9aGc7m+XXFruPKZEgxAoGBAMA96jsow7CzulU+GRW8
|
||||
Njg4zWuAEVErgPoNBcOXAVWLCTU/qGIEMNpZL6Ok34kf13pJDMjQ8eDuQHu5CSqf
|
||||
0ul5Zy85fwfVq2IvNAyYT8eflQprTejFw22CHhfPBfADVW9ro8dK/Jw+J/31Vh7V
|
||||
ILKEQKmPPzKs7kp/7Nz+2cT3
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAsmAqn3hYd/YZcrfgqM1Q6xgHI50EBckbOkfCqTWS1yVFZjLF
|
||||
bMehWb9xGFZJD21A5sxl4xelIWblhety+YTVa/mn2CEJh3je069oeULfXdzhhHyf
|
||||
/ci0IloJhvX+2RJ+176uTKKcWhuOtNVs5VeFoHDoUcISnTqkaVyWeeLfafgrOW7w
|
||||
N8ip128nuBx19ylIygb/DELmjKRRCSpx2vOw2JErTM8L5r0f4eWdqiwBOwu0NHWy
|
||||
Svh9YG8B31UPga4I8FbFhybOP9cQNQPafOSfjwuZoi5CAtyJbwT7KyII9iMD74bZ
|
||||
1mTx2xokmQ2TeiCSKSF8Mx9/8Gq+95mzvvIbRwIDAQABAoIBAHNt++caj9WBclJk
|
||||
X4Oc6eJYuDX5o+LCk1YRngy12IJVYiWScWPFg8p6MouXOsw63Sb92mksofWNirYw
|
||||
+UQzC5FGC7G3H12FgFzoQ+lEtxscluuPYlFukfMw5L1rbzG14FNo145MJHXDI4Qu
|
||||
ILwA+T4sEorl1fndOwvbmJzjjcQaeRNz7/R9e6QTOlZ2+IEMKnHSBXXGJbDj6mPN
|
||||
+f1/ec6nVENdxazgRCi0xfinyft4Ipst93Eb+wGcpk+J43aF+0leWQCdl6Y9U1Lz
|
||||
zpv5H5XOQdwpX+dpuioRp73zwPwIialq+hTUN28Bn9U1jW2tjxUl/vgIpjy1s94a
|
||||
UipRwSECgYEA57vYB+wGnxQxY9IPpr9H/y3HciIwCnuOEsWBzjYe8sIqBif2tEpO
|
||||
OgDZZMQY7+JJrDQbDRs442TuRjKhJ5hiW+MyoiFWaYkBBoNVM8RBTkIjHfrh+uB2
|
||||
XT15FbEyyxo3n9QY610ZJFRnW4Uf5V0osjOqqUgQRrVXvamk6NQH6FkCgYEAxQ3v
|
||||
jFYPL3EkZe1br6X0RM42ykGv5Di5Q6NnjpSPcyn9a2obA1cZuCd5S1lhrkuZGsdI
|
||||
iFapeL+7vpts9gu9/ii9y+CgEKplOMmm0ZrChBKAcXMZvdDKV3y5SmTMZPas4X5i
|
||||
hqNqatx9/J93sMYWc0CuoosDEJYKtSz8GE+1rJ8CgYAmp5rdl21zU7b5Y6zgr7+e
|
||||
vVArpbBFz15fmzqP309CR0kjRb9NS6fI3SNmP5+5RBHt+7MXeJcAt3FXnFJtfGnL
|
||||
0hY8HTuA1y2onHe17uLF3xpkgdj4NEEKRJrSF4DViEYHDyYo/JqZCMtE5OvxIp0L
|
||||
PLsXCcJNSSqdpJKxk8zN4QKBgEuoxSAh7uStUWddUkXHt1kvwDO6MtmyuddxhxJk
|
||||
kguKxMWYUNTgfXyKk3TN1caBOkDg4UWP2LQHEgPmU1jJO2K5q9362hpsAj9ilY2H
|
||||
GUZygCSPKAQMhZQ/zDj3KM9fMxPFXfkKB5MOI8V6SQ9zjy0jWaoJK90TbvsPUZ/Y
|
||||
Aw5LAoGADifZwCHPiXhTfJjOom2uBgXmL03yTXcCw4EDIX3ZR0sP6ACPQq4T4jxZ
|
||||
UJLXLjOb2pzCq0c5+k0cG6ahYINq4tGOo+vQ9fDvhKg0nlf1FrzxSd7S12o+un2q
|
||||
+U+dBllYIDlRMgMhXu9CxFDjUsCwPRmsBvmVZiH4XSs6QVnfn90=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDcDt23t6ioBoHG
|
||||
/Y2mOjxntWQa9dP3eNl+mAC6425DlEtyc6czNAIKuuM9wt+wAwDQAgrd5RaxdcpJ
|
||||
H1JlMkEtBFkIkdn0Ag98D7nwlVA9ON3xQi5Bkl+sN/oWOE8lOwvNyNNT6ZPu3qUS
|
||||
KY8SXZVY315daqz2eRWsm2otqjqbWGhh9c7FGHr3r9aAG08dyaO6OvK14GJIhNV+
|
||||
UOPH5hDMMaxurDt8znaSUw93b7D++aEninGro/s2LY4G91dgM8i4t88UWobXpqs5
|
||||
GMGTI0InLX2I66HkteH4RRfXXC9svA2CxN3yP294FIP7gdRQ1CGJeJcluzsjtx0V
|
||||
i2G9vrT1AgMBAAECggEAF0obfQ4a82183qqHC0iui+tOpOvPeyl3G0bLDPx09wIC
|
||||
2iITV//xF2GgGzE8q0wmEd2leMZ+GFn3BrYh6kPfUfxbz+RfxMtTCDZB34xt6YzT
|
||||
MG1op9ft+DQUa7WZ6r7NCQJwGzllRqqZncp4MeFlpPo+6nQXyh4WhSYNnredbENE
|
||||
uPZ63Kme4RZfMvtVso+XgAQM3oDih0onv1YitmNQpL9rRzlthTfybAT4737DBINq
|
||||
zsmBNE6QIsXnSKpzo11OtDgof2QM9ac6eAXf73oTpDxfodwCotILytKn+8WYvlR+
|
||||
T15uuknb4M3XI1FPVolkF4qtK5SLAAbVzV4DsCmuIQKBgQD6bTKKbL2huvU6dEKx
|
||||
bgS079LfQUxxOTClgwkhVsMxRtvcPBnHYMAsPK4mnMhEh9x+TF6wxMx0pmhQluPI
|
||||
ZULNBj/qdoiBL0RwVLA+9jgE0NeWB3XXFDsEavQBr9Q8CC0uzrsgsxFcvHpqqs2Q
|
||||
RtngxRWtJP06D6mKC23s4YjDHwKBgQDg9KUCFqOmWcRXyeg9gYMC4jFFQw4lUQBd
|
||||
sYpqSMHDw1b+T1W/dCPbwbxZL/+d8y930BYy9QYDtQwHdLyXCH0pHM7S6rfgr5xk
|
||||
2Szd8xBUIqmeV/zcR00mTeQHJ1M50VHfclAVgZgkpWSoLwbX+bXyx/mfqLAtynZ5
|
||||
yU9RfrT5awKBgQC0uJ8TlFvZXjFgyMvkfY/5/2R/ZwFCaFI573FkVNeyNP+vVNQJ
|
||||
tUGZ6wSGqvg/tIgjwPtIuA0QVZLMLcgeMy1dBhiUHIxwJetO4V77YPaWSxx5kdKx
|
||||
r1DT5FdI7FnOJNxufhQ/CdsKwJ3bYn3Mk8TiV3hIJnx0LR9dltfybeQjYwKBgDOY
|
||||
6aApATBOtrJMJXC2HA61QwfX8Y6tnZ/f8RefyJHWZEXAfLKFORRWw5TRZZgdB247
|
||||
1Furx81h4Xh0Vi1uTQb5DJdkLvjiTsTy60+dSMmDidQ/6ke8Mv3uL7dUVcqVMGpI
|
||||
FgZYy0TcitHot3EiXZFqPN9aGc7m+XXFruPKZEgxAoGBAMA96jsow7CzulU+GRW8
|
||||
Njg4zWuAEVErgPoNBcOXAVWLCTU/qGIEMNpZL6Ok34kf13pJDMjQ8eDuQHu5CSqf
|
||||
0ul5Zy85fwfVq2IvNAyYT8eflQprTejFw22CHhfPBfADVW9ro8dK/Jw+J/31Vh7V
|
||||
ILKEQKmPPzKs7kp/7Nz+2cT3
|
||||
-----END PRIVATE KEY-----
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICuDCCAaACCQC7PQmrxgWOlTANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJs
|
||||
ZWNlcGluLTIwMjItMDUtMTkwIBcNMjIwNTE5MTI1NjA0WhgPMzAyMTA5MTkxMjU2
|
||||
MDRaMB0xGzAZBgNVBAMMEmxlY2VwaW4tMjAyMi0wNS0xOTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALJgKp94WHf2GXK34KjNUOsYByOdBAXJGzpHwqk1
|
||||
ktclRWYyxWzHoVm/cRhWSQ9tQObMZeMXpSFm5YXrcvmE1Wv5p9ghCYd43tOvaHlC
|
||||
313c4YR8n/3ItCJaCYb1/tkSfte+rkyinFobjrTVbOVXhaBw6FHCEp06pGlclnni
|
||||
32n4Kzlu8DfIqddvJ7gcdfcpSMoG/wxC5oykUQkqcdrzsNiRK0zPC+a9H+Hlnaos
|
||||
ATsLtDR1skr4fWBvAd9VD4GuCPBWxYcmzj/XEDUD2nzkn48LmaIuQgLciW8E+ysi
|
||||
CPYjA++G2dZk8dsaJJkNk3ogkikhfDMff/BqvveZs77yG0cCAwEAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEADymHk+wLJAdv3p+4hHo57VLaBtwVYXc5oRUbUzgMYTTtPWIs
|
||||
xuILEqXftMspt6PzdEt0V1WeCWNyypsAbur/CKpAOoVjBDPIo09TiYnYIn9xt5wQ
|
||||
AmR5kVEZheuazcvzW3C9NAY1T6QDmxNvFCiCXRbtklOg2HqFDZX+pkj8CylQ9TDk
|
||||
rroUg17b/FD1ds1uyPXzucEWfxqkOaujvsCnzrbFs9luB5VfM+QzLU+l9QRN9Tmj
|
||||
z7CpGuP6vKvhXJLUjXkZ0q5JyL5wEAe6Ttbu+c/8HhPFKQsW6q/lQSDo0v0LGDrd
|
||||
ikjWXhSrVjd8+qTTVgia/UNqv/wi+bkWnVdRzQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL
|
||||
BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ
|
||||
Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu
|
||||
dDERMA8GA1UEAwwIZ293YXMuY24wIBcNMjQwMjE4MDIwOTI2WhgPMjEyNDAxMjUw
|
||||
MjA5MjZaMHAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlDaG9uZ3FpbmcxEjAQBgNV
|
||||
BAcMCUNob25ncWluZzEOMAwGA1UECgwFZ293YXMxFjAUBgNVBAsMDUlUIERlcGFy
|
||||
dG1lbnQxETAPBgNVBAMMCGdvd2FzLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA3A7dt7eoqAaBxv2Npjo8Z7VkGvXT93jZfpgAuuNuQ5RLcnOnMzQC
|
||||
CrrjPcLfsAMA0AIK3eUWsXXKSR9SZTJBLQRZCJHZ9AIPfA+58JVQPTjd8UIuQZJf
|
||||
rDf6FjhPJTsLzcjTU+mT7t6lEimPEl2VWN9eXWqs9nkVrJtqLao6m1hoYfXOxRh6
|
||||
96/WgBtPHcmjujryteBiSITVflDjx+YQzDGsbqw7fM52klMPd2+w/vmhJ4pxq6P7
|
||||
Ni2OBvdXYDPIuLfPFFqG16arORjBkyNCJy19iOuh5LXh+EUX11wvbLwNgsTd8j9v
|
||||
eBSD+4HUUNQhiXiXJbs7I7cdFYthvb609QIDAQABo1MwUTAdBgNVHQ4EFgQUdI8p
|
||||
aY1A47rWCRvQKSTRCCk6FoMwHwYDVR0jBBgwFoAUdI8paY1A47rWCRvQKSTRCCk6
|
||||
FoMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArMCAfqidgXL7
|
||||
cW5TAZTCqnUeKzbbqMJgk6iFsma8scMRsUXz9ZhF0UVf98376KvoJpy4vd81afbi
|
||||
TehQ8wVBuKTtkHeh/MkXMWC/FU4HqSjtvxpic2+Or5dMjIrfa5VYPgzfqNaBIUh4
|
||||
InD5lo8b/n5V+jdwX7RX9VYAKug6QZlCg5YSKIvgNRChb36JmrGcvsp5R0Vejnii
|
||||
e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ
|
||||
5yVNeSxX2zqasZvP/fRy+3I5iVilxtKvJuVpPZ0UZzGS0CJ/lF67ntibktiPa3sR
|
||||
D8HixYbEDg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
@@ -1,17 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICuDCCAaACCQC7PQmrxgWOlTANBgkqhkiG9w0BAQsFADAdMRswGQYDVQQDDBJs
|
||||
ZWNlcGluLTIwMjItMDUtMTkwIBcNMjIwNTE5MTI1NjA0WhgPMzAyMTA5MTkxMjU2
|
||||
MDRaMB0xGzAZBgNVBAMMEmxlY2VwaW4tMjAyMi0wNS0xOTCCASIwDQYJKoZIhvcN
|
||||
AQEBBQADggEPADCCAQoCggEBALJgKp94WHf2GXK34KjNUOsYByOdBAXJGzpHwqk1
|
||||
ktclRWYyxWzHoVm/cRhWSQ9tQObMZeMXpSFm5YXrcvmE1Wv5p9ghCYd43tOvaHlC
|
||||
313c4YR8n/3ItCJaCYb1/tkSfte+rkyinFobjrTVbOVXhaBw6FHCEp06pGlclnni
|
||||
32n4Kzlu8DfIqddvJ7gcdfcpSMoG/wxC5oykUQkqcdrzsNiRK0zPC+a9H+Hlnaos
|
||||
ATsLtDR1skr4fWBvAd9VD4GuCPBWxYcmzj/XEDUD2nzkn48LmaIuQgLciW8E+ysi
|
||||
CPYjA++G2dZk8dsaJJkNk3ogkikhfDMff/BqvveZs77yG0cCAwEAATANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEADymHk+wLJAdv3p+4hHo57VLaBtwVYXc5oRUbUzgMYTTtPWIs
|
||||
xuILEqXftMspt6PzdEt0V1WeCWNyypsAbur/CKpAOoVjBDPIo09TiYnYIn9xt5wQ
|
||||
AmR5kVEZheuazcvzW3C9NAY1T6QDmxNvFCiCXRbtklOg2HqFDZX+pkj8CylQ9TDk
|
||||
rroUg17b/FD1ds1uyPXzucEWfxqkOaujvsCnzrbFs9luB5VfM+QzLU+l9QRN9Tmj
|
||||
z7CpGuP6vKvhXJLUjXkZ0q5JyL5wEAe6Ttbu+c/8HhPFKQsW6q/lQSDo0v0LGDrd
|
||||
ikjWXhSrVjd8+qTTVgia/UNqv/wi+bkWnVdRzQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCAqugAwIBAgIUFAnC6268dp/z1DR9E1UepiWgWzkwDQYJKoZIhvcNAQEL
|
||||
BQAwcDELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCUNob25ncWluZzESMBAGA1UEBwwJ
|
||||
Q2hvbmdxaW5nMQ4wDAYDVQQKDAVnb3dhczEWMBQGA1UECwwNSVQgRGVwYXJ0bWVu
|
||||
dDERMA8GA1UEAwwIZ293YXMuY24wIBcNMjQwMjE4MDIwOTI2WhgPMjEyNDAxMjUw
|
||||
MjA5MjZaMHAxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlDaG9uZ3FpbmcxEjAQBgNV
|
||||
BAcMCUNob25ncWluZzEOMAwGA1UECgwFZ293YXMxFjAUBgNVBAsMDUlUIERlcGFy
|
||||
dG1lbnQxETAPBgNVBAMMCGdvd2FzLmNuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA3A7dt7eoqAaBxv2Npjo8Z7VkGvXT93jZfpgAuuNuQ5RLcnOnMzQC
|
||||
CrrjPcLfsAMA0AIK3eUWsXXKSR9SZTJBLQRZCJHZ9AIPfA+58JVQPTjd8UIuQZJf
|
||||
rDf6FjhPJTsLzcjTU+mT7t6lEimPEl2VWN9eXWqs9nkVrJtqLao6m1hoYfXOxRh6
|
||||
96/WgBtPHcmjujryteBiSITVflDjx+YQzDGsbqw7fM52klMPd2+w/vmhJ4pxq6P7
|
||||
Ni2OBvdXYDPIuLfPFFqG16arORjBkyNCJy19iOuh5LXh+EUX11wvbLwNgsTd8j9v
|
||||
eBSD+4HUUNQhiXiXJbs7I7cdFYthvb609QIDAQABo1MwUTAdBgNVHQ4EFgQUdI8p
|
||||
aY1A47rWCRvQKSTRCCk6FoMwHwYDVR0jBBgwFoAUdI8paY1A47rWCRvQKSTRCCk6
|
||||
FoMwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEArMCAfqidgXL7
|
||||
cW5TAZTCqnUeKzbbqMJgk6iFsma8scMRsUXz9ZhF0UVf98376KvoJpy4vd81afbi
|
||||
TehQ8wVBuKTtkHeh/MkXMWC/FU4HqSjtvxpic2+Or5dMjIrfa5VYPgzfqNaBIUh4
|
||||
InD5lo8b/n5V+jdwX7RX9VYAKug6QZlCg5YSKIvgNRChb36JmrGcvsp5R0Vejnii
|
||||
e3oowvgwikqm6XR6BEcRpPkztqcKST7jPFGHiXWsAqiibc+/plMW9qebhfMXEGhQ
|
||||
5yVNeSxX2zqasZvP/fRy+3I5iVilxtKvJuVpPZ0UZzGS0CJ/lF67ntibktiPa3sR
|
||||
D8HixYbEDg==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
25
electron/res/linux/aria2/aria2.conf
Normal file
25
electron/res/linux/aria2/aria2.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
#允许rpc
|
||||
enable-rpc=true
|
||||
#允许非外部访问
|
||||
rpc-listen-all=true
|
||||
|
||||
#最大同时下载数(任务数), 路由建议值: 3
|
||||
max-concurrent-downloads=3
|
||||
#断点续传
|
||||
continue=true
|
||||
#同服务器连接数
|
||||
max-connection-per-server=10
|
||||
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
|
||||
min-split-size=10M
|
||||
#单文件最大线程数, 路由建议值: 5
|
||||
split=10
|
||||
#下载速度限制
|
||||
max-overall-download-limit=0
|
||||
#单文件速度限制
|
||||
max-download-limit=0
|
||||
#上传速度限制
|
||||
max-overall-upload-limit=0
|
||||
#单文件速度限制
|
||||
max-upload-limit=0
|
||||
|
||||
check-certificate=false
|
||||
BIN
electron/res/linux/aria2/arm64/aria2c
Executable file
BIN
electron/res/linux/aria2/arm64/aria2c
Executable file
Binary file not shown.
BIN
electron/res/linux/aria2/armv7l/aria2c
Executable file
BIN
electron/res/linux/aria2/armv7l/aria2c
Executable file
Binary file not shown.
BIN
electron/res/linux/aria2/x64/aria2c
Executable file
BIN
electron/res/linux/aria2/x64/aria2c
Executable file
Binary file not shown.
Binary file not shown.
@@ -1,126 +0,0 @@
|
||||
|
||||
LICENSE ISSUES
|
||||
==============
|
||||
|
||||
The OpenSSL toolkit stays under a dual license, i.e. both the conditions of
|
||||
the OpenSSL License and the original SSLeay license apply to the toolkit.
|
||||
See below for the actual license texts. Actually both licenses are BSD-style
|
||||
Open Source licenses. In case of any license issues related to OpenSSL
|
||||
please contact openssl-core@openssl.org.
|
||||
|
||||
OpenSSL License
|
||||
---------------
|
||||
|
||||
/* ====================================================================
|
||||
* Copyright (c) 1998-2016 The OpenSSL Project. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this
|
||||
* software must display the following acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
|
||||
*
|
||||
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
|
||||
* endorse or promote products derived from this software without
|
||||
* prior written permission. For written permission, please contact
|
||||
* openssl-core@openssl.org.
|
||||
*
|
||||
* 5. Products derived from this software may not be called "OpenSSL"
|
||||
* nor may "OpenSSL" appear in their names without prior written
|
||||
* permission of the OpenSSL Project.
|
||||
*
|
||||
* 6. Redistributions of any form whatsoever must retain the following
|
||||
* acknowledgment:
|
||||
* "This product includes software developed by the OpenSSL Project
|
||||
* for use in the OpenSSL Toolkit (http://www.openssl.org/)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
|
||||
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
|
||||
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
* ====================================================================
|
||||
*
|
||||
* This product includes cryptographic software written by Eric Young
|
||||
* (eay@cryptsoft.com). This product includes software written by Tim
|
||||
* Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
*/
|
||||
|
||||
Original SSLeay License
|
||||
-----------------------
|
||||
|
||||
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This package is an SSL implementation written
|
||||
* by Eric Young (eay@cryptsoft.com).
|
||||
* The implementation was written so as to conform with Netscapes SSL.
|
||||
*
|
||||
* This library is free for commercial and non-commercial use as long as
|
||||
* the following conditions are aheared to. The following conditions
|
||||
* apply to all code found in this distribution, be it the RC4, RSA,
|
||||
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
|
||||
* included with this distribution is covered by the same copyright terms
|
||||
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
|
||||
*
|
||||
* Copyright remains Eric Young's, and as such any Copyright notices in
|
||||
* the code are not to be removed.
|
||||
* If this package is used in a product, Eric Young should be given attribution
|
||||
* as the author of the parts of the library used.
|
||||
* This can be in the form of a textual message at program startup or
|
||||
* in documentation (online or textual) provided with the package.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* "This product includes cryptographic software written by
|
||||
* Eric Young (eay@cryptsoft.com)"
|
||||
* The word 'cryptographic' can be left out if the rouines from the library
|
||||
* being used are not cryptographic related :-).
|
||||
* 4. If you include any Windows specific code (or a derivative thereof) from
|
||||
* the apps directory (application code) you must include an acknowledgement:
|
||||
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* The licence and distribution terms for any publically available version or
|
||||
* derivative of this code cannot be changed. i.e. this code cannot simply be
|
||||
* copied and put under another distribution licence
|
||||
* [including the GNU Public Licence.]
|
||||
*/
|
||||
@@ -1,59 +0,0 @@
|
||||
=============================================================================
|
||||
OpenSSL v1.0.2q Precompiled Binaries for Win32
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Release Information ***
|
||||
|
||||
Release Date: Nov 22, 2018
|
||||
|
||||
Author: Frederik A. Winkelsdorf (opendec.wordpress.com)
|
||||
for the Indy Project (www.indyproject.org)
|
||||
|
||||
Requirements: Indy 10.5.5+ (SVN Version or Delphi 2009 and newer)
|
||||
|
||||
Dependencies: The libraries have no noteworthy dependencies
|
||||
|
||||
Installation: Copy both DLL files into your application directory
|
||||
|
||||
Supported OS: Windows 2000 up to Windows 10
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Legal Disclaimer ***
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ITS AUTHOR AND THE INDY PROJECT "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
OpenSSL license terms are provided in the file "OpenSSL License.txt".
|
||||
|
||||
PLEASE CHECK IF YOU NEED TO COMPLY WITH EXPORT RESTRICTIONS FOR CRYPTOGRAPHIC
|
||||
SOFTWARE AND/OR PATENTS.
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
*** Build Information Win32 ***
|
||||
|
||||
Built with: Microsoft Visual C++ 2008 Express Edition
|
||||
The Netwide Assembler (NASM) v2.11.08 Win32
|
||||
Strawberry Perl v5.22.0.1 Win32 Portable
|
||||
Windows PowerShell
|
||||
FinalBuilder 7
|
||||
|
||||
Commands: perl configure VC-WIN32
|
||||
ms\do_nasm
|
||||
adjusted ms\ntdll.mak (replaced "/MD" with "/MT")
|
||||
adjusted ms\version32.rc (Indy Information inserted)
|
||||
nmake -f ms\ntdll.mak
|
||||
nmake -f ms\ntdll.mak test
|
||||
editbin.exe /rebase:base=0x11000000 libeay32.dll
|
||||
editbin.exe /rebase:base=0x12000000 ssleay32.dll
|
||||
|
||||
=============================================================================
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
25
electron/res/win/aria2/aria2.conf
Normal file
25
electron/res/win/aria2/aria2.conf
Normal file
@@ -0,0 +1,25 @@
|
||||
#允许rpc
|
||||
enable-rpc=true
|
||||
#允许非外部访问
|
||||
rpc-listen-all=true
|
||||
|
||||
#最大同时下载数(任务数), 路由建议值: 3
|
||||
max-concurrent-downloads=3
|
||||
#断点续传
|
||||
continue=true
|
||||
#同服务器连接数
|
||||
max-connection-per-server=10
|
||||
#最小文件分片大小, 下载线程数上限取决于能分出多少片, 对于小文件重要
|
||||
min-split-size=10M
|
||||
#单文件最大线程数, 路由建议值: 5
|
||||
split=10
|
||||
#下载速度限制
|
||||
max-overall-download-limit=0
|
||||
#单文件速度限制
|
||||
max-download-limit=0
|
||||
#上传速度限制
|
||||
max-overall-upload-limit=0
|
||||
#单文件速度限制
|
||||
max-upload-limit=0
|
||||
|
||||
check-certificate=false
|
||||
BIN
electron/res/win/aria2/aria2c.exe
Executable file
BIN
electron/res/win/aria2/aria2c.exe
Executable file
Binary file not shown.
239
electron/res/win/openssl/CA.pl
Executable file
239
electron/res/win/openssl/CA.pl
Executable file
@@ -0,0 +1,239 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
#
|
||||
# Wrapper around the ca to make it easier to use
|
||||
#
|
||||
# WARNING: do not edit!
|
||||
# Generated by makefile from apps\CA.pl.in
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my $verbose = 1;
|
||||
my @OPENSSL_CMDS = ("req", "ca", "pkcs12", "x509", "verify");
|
||||
|
||||
my $openssl = $ENV{'OPENSSL'} // "openssl";
|
||||
$ENV{'OPENSSL'} = $openssl;
|
||||
my $OPENSSL_CONFIG = $ENV{"OPENSSL_CONFIG"} // "";
|
||||
|
||||
# Command invocations.
|
||||
my $REQ = "$openssl req $OPENSSL_CONFIG";
|
||||
my $CA = "$openssl ca $OPENSSL_CONFIG";
|
||||
my $VERIFY = "$openssl verify";
|
||||
my $X509 = "$openssl x509";
|
||||
my $PKCS12 = "$openssl pkcs12";
|
||||
|
||||
# Default values for various configuration settings.
|
||||
my $CATOP = "./demoCA";
|
||||
my $CAKEY = "cakey.pem";
|
||||
my $CAREQ = "careq.pem";
|
||||
my $CACERT = "cacert.pem";
|
||||
my $CACRL = "crl.pem";
|
||||
my $DAYS = "-days 365";
|
||||
my $CADAYS = "-days 1095"; # 3 years
|
||||
my $EXTENSIONS = "-extensions v3_ca";
|
||||
my $POLICY = "-policy policy_anything";
|
||||
my $NEWKEY = "newkey.pem";
|
||||
my $NEWREQ = "newreq.pem";
|
||||
my $NEWCERT = "newcert.pem";
|
||||
my $NEWP12 = "newcert.p12";
|
||||
|
||||
# Commandline parsing
|
||||
my %EXTRA;
|
||||
my $WHAT = shift @ARGV || "";
|
||||
@ARGV = parse_extra(@ARGV);
|
||||
my $RET = 0;
|
||||
|
||||
# Split out "-extra-CMD value", and return new |@ARGV|. Fill in
|
||||
# |EXTRA{CMD}| with list of values.
|
||||
sub parse_extra
|
||||
{
|
||||
foreach ( @OPENSSL_CMDS ) {
|
||||
$EXTRA{$_} = '';
|
||||
}
|
||||
|
||||
my @result;
|
||||
while ( scalar(@_) > 0 ) {
|
||||
my $arg = shift;
|
||||
if ( $arg !~ m/-extra-([a-z0-9]+)/ ) {
|
||||
push @result, $arg;
|
||||
next;
|
||||
}
|
||||
$arg =~ s/-extra-//;
|
||||
die("Unknown \"-${arg}-extra\" option, exiting")
|
||||
unless scalar grep { $arg eq $_ } @OPENSSL_CMDS;
|
||||
$EXTRA{$arg} .= " " . shift;
|
||||
}
|
||||
return @result;
|
||||
}
|
||||
|
||||
|
||||
# See if reason for a CRL entry is valid; exit if not.
|
||||
sub crl_reason_ok
|
||||
{
|
||||
my $r = shift;
|
||||
|
||||
if ($r eq 'unspecified' || $r eq 'keyCompromise'
|
||||
|| $r eq 'CACompromise' || $r eq 'affiliationChanged'
|
||||
|| $r eq 'superseded' || $r eq 'cessationOfOperation'
|
||||
|| $r eq 'certificateHold' || $r eq 'removeFromCRL') {
|
||||
return 1;
|
||||
}
|
||||
print STDERR "Invalid CRL reason; must be one of:\n";
|
||||
print STDERR " unspecified, keyCompromise, CACompromise,\n";
|
||||
print STDERR " affiliationChanged, superseded, cessationOfOperation\n";
|
||||
print STDERR " certificateHold, removeFromCRL";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Copy a PEM-format file; return like exit status (zero means ok)
|
||||
sub copy_pemfile
|
||||
{
|
||||
my ($infile, $outfile, $bound) = @_;
|
||||
my $found = 0;
|
||||
|
||||
open IN, $infile || die "Cannot open $infile, $!";
|
||||
open OUT, ">$outfile" || die "Cannot write to $outfile, $!";
|
||||
while (<IN>) {
|
||||
$found = 1 if /^-----BEGIN.*$bound/;
|
||||
print OUT $_ if $found;
|
||||
$found = 2, last if /^-----END.*$bound/;
|
||||
}
|
||||
close IN;
|
||||
close OUT;
|
||||
return $found == 2 ? 0 : 1;
|
||||
}
|
||||
|
||||
# Wrapper around system; useful for debugging. Returns just the exit status
|
||||
sub run
|
||||
{
|
||||
my $cmd = shift;
|
||||
print "====\n$cmd\n" if $verbose;
|
||||
my $status = system($cmd);
|
||||
print "==> $status\n====\n" if $verbose;
|
||||
return $status >> 8;
|
||||
}
|
||||
|
||||
|
||||
if ( $WHAT =~ /^(-\?|-h|-help)$/ ) {
|
||||
print STDERR <<EOF;
|
||||
Usage:
|
||||
CA.pl -newcert | -newreq | -newreq-nodes | -xsign | -sign | -signCA | -signcert | -crl | -newca [-extra-cmd parameter]
|
||||
CA.pl -pkcs12 [certname]
|
||||
CA.pl -verify certfile ...
|
||||
CA.pl -revoke certfile [reason]
|
||||
EOF
|
||||
exit 0;
|
||||
}
|
||||
|
||||
if ($WHAT eq '-newcert' ) {
|
||||
# create a certificate
|
||||
$RET = run("$REQ -new -x509 -keyout $NEWKEY -out $NEWCERT $DAYS"
|
||||
. " $EXTRA{req}");
|
||||
print "Cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-precert' ) {
|
||||
# create a pre-certificate
|
||||
$RET = run("$REQ -x509 -precert -keyout $NEWKEY -out $NEWCERT $DAYS"
|
||||
. " $EXTRA{req}");
|
||||
print "Pre-cert is in $NEWCERT, private key is in $NEWKEY\n" if $RET == 0;
|
||||
} elsif ($WHAT =~ /^\-newreq(\-nodes)?$/ ) {
|
||||
# create a certificate request
|
||||
$RET = run("$REQ -new $1 -keyout $NEWKEY -out $NEWREQ $DAYS $EXTRA{req}");
|
||||
print "Request is in $NEWREQ, private key is in $NEWKEY\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-newca' ) {
|
||||
# create the directory hierarchy
|
||||
my @dirs = ( "${CATOP}", "${CATOP}/certs", "${CATOP}/crl",
|
||||
"${CATOP}/newcerts", "${CATOP}/private" );
|
||||
die "${CATOP}/index.txt exists.\nRemove old sub-tree to proceed,"
|
||||
if -f "${CATOP}/index.txt";
|
||||
die "${CATOP}/serial exists.\nRemove old sub-tree to proceed,"
|
||||
if -f "${CATOP}/serial";
|
||||
foreach my $d ( @dirs ) {
|
||||
if ( -d $d ) {
|
||||
warn "Directory $d exists" if -d $d;
|
||||
} else {
|
||||
mkdir $d or die "Can't mkdir $d, $!";
|
||||
}
|
||||
}
|
||||
|
||||
open OUT, ">${CATOP}/index.txt";
|
||||
close OUT;
|
||||
open OUT, ">${CATOP}/crlnumber";
|
||||
print OUT "01\n";
|
||||
close OUT;
|
||||
# ask user for existing CA certificate
|
||||
print "CA certificate filename (or enter to create)\n";
|
||||
my $FILE;
|
||||
$FILE = "" unless defined($FILE = <STDIN>);
|
||||
$FILE =~ s{\R$}{};
|
||||
if ($FILE ne "") {
|
||||
copy_pemfile($FILE,"${CATOP}/private/$CAKEY", "PRIVATE");
|
||||
copy_pemfile($FILE,"${CATOP}/$CACERT", "CERTIFICATE");
|
||||
} else {
|
||||
print "Making CA certificate ...\n";
|
||||
$RET = run("$REQ -new -keyout ${CATOP}/private/$CAKEY"
|
||||
. " -out ${CATOP}/$CAREQ $EXTRA{req}");
|
||||
$RET = run("$CA -create_serial"
|
||||
. " -out ${CATOP}/$CACERT $CADAYS -batch"
|
||||
. " -keyfile ${CATOP}/private/$CAKEY -selfsign"
|
||||
. " $EXTENSIONS"
|
||||
. " -infiles ${CATOP}/$CAREQ $EXTRA{ca}") if $RET == 0;
|
||||
print "CA certificate is in ${CATOP}/$CACERT\n" if $RET == 0;
|
||||
}
|
||||
} elsif ($WHAT eq '-pkcs12' ) {
|
||||
my $cname = $ARGV[0];
|
||||
$cname = "My Certificate" unless defined $cname;
|
||||
$RET = run("$PKCS12 -in $NEWCERT -inkey $NEWKEY"
|
||||
. " -certfile ${CATOP}/$CACERT -out $NEWP12"
|
||||
. " -export -name \"$cname\" $EXTRA{pkcs12}");
|
||||
print "PKCS #12 file is in $NEWP12\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-xsign' ) {
|
||||
$RET = run("$CA $POLICY -infiles $NEWREQ $EXTRA{ca}");
|
||||
} elsif ($WHAT eq '-sign' ) {
|
||||
$RET = run("$CA $POLICY -out $NEWCERT"
|
||||
. " -infiles $NEWREQ $EXTRA{ca}");
|
||||
print "Signed certificate is in $NEWCERT\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-signCA' ) {
|
||||
$RET = run("$CA $POLICY -out $NEWCERT"
|
||||
. " $EXTENSIONS -infiles $NEWREQ $EXTRA{ca}");
|
||||
print "Signed CA certificate is in $NEWCERT\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-signcert' ) {
|
||||
$RET = run("$X509 -x509toreq -in $NEWREQ -signkey $NEWREQ"
|
||||
. " -out tmp.pem $EXTRA{x509}");
|
||||
$RET = run("$CA $POLICY -out $NEWCERT"
|
||||
. "-infiles tmp.pem $EXTRA{ca}") if $RET == 0;
|
||||
print "Signed certificate is in $NEWCERT\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-verify' ) {
|
||||
my @files = @ARGV ? @ARGV : ( $NEWCERT );
|
||||
foreach my $file (@files) {
|
||||
# -CAfile quoted for VMS, since the C RTL downcases all unquoted
|
||||
# arguments to C programs
|
||||
my $status = run("$VERIFY \"-CAfile\" ${CATOP}/$CACERT $file $EXTRA{verify}");
|
||||
$RET = $status if $status != 0;
|
||||
}
|
||||
} elsif ($WHAT eq '-crl' ) {
|
||||
$RET = run("$CA -gencrl -out ${CATOP}/crl/$CACRL $EXTRA{ca}");
|
||||
print "Generated CRL is in ${CATOP}/crl/$CACRL\n" if $RET == 0;
|
||||
} elsif ($WHAT eq '-revoke' ) {
|
||||
my $cname = $ARGV[0];
|
||||
if (!defined $cname) {
|
||||
print "Certificate filename is required; reason optional.\n";
|
||||
exit 1;
|
||||
}
|
||||
my $reason = $ARGV[1];
|
||||
$reason = " -crl_reason $reason"
|
||||
if defined $reason && crl_reason_ok($reason);
|
||||
$RET = run("$CA -revoke \"$cname\"" . $reason . $EXTRA{ca});
|
||||
} else {
|
||||
print STDERR "Unknown arg \"$WHAT\"\n";
|
||||
print STDERR "Use -help for help.\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
exit $RET;
|
||||
BIN
electron/res/win/openssl/capi.dll
Executable file
BIN
electron/res/win/openssl/capi.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/dasync.dll
Executable file
BIN
electron/res/win/openssl/dasync.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/legacy.dll
Executable file
BIN
electron/res/win/openssl/legacy.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/libcrypto-3-x64.dll
Executable file
BIN
electron/res/win/openssl/libcrypto-3-x64.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/libssl-3-x64.dll
Executable file
BIN
electron/res/win/openssl/libssl-3-x64.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/loader_attic.dll
Executable file
BIN
electron/res/win/openssl/loader_attic.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/openssl.exe
Executable file
BIN
electron/res/win/openssl/openssl.exe
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/ossltest.dll
Executable file
BIN
electron/res/win/openssl/ossltest.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/p_minimal.dll
Executable file
BIN
electron/res/win/openssl/p_minimal.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/p_test.dll
Executable file
BIN
electron/res/win/openssl/p_test.dll
Executable file
Binary file not shown.
BIN
electron/res/win/openssl/padlock.dll
Executable file
BIN
electron/res/win/openssl/padlock.dll
Executable file
Binary file not shown.
218
electron/res/win/openssl/progs.pl
Executable file
218
electron/res/win/openssl/progs.pl
Executable file
@@ -0,0 +1,218 @@
|
||||
#! /usr/bin/env perl
|
||||
# Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
# Generate progs.h file by looking for command mains in list of C files
|
||||
# passed on the command line.
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use lib '.';
|
||||
use configdata qw/@disablables %unified_info/;
|
||||
|
||||
my $opt = shift @ARGV;
|
||||
die "Unrecognised option, must be -C or -H\n"
|
||||
unless ($opt eq '-H' || $opt eq '-C');
|
||||
|
||||
my %commands = ();
|
||||
my $cmdre = qr/^\s*int\s+([a-z_][a-z0-9_]*)_main\(\s*int\s+argc\s*,/;
|
||||
my $apps_openssl = shift @ARGV;
|
||||
my $YEAR = [gmtime($ENV{SOURCE_DATE_EPOCH} || time())]->[5] + 1900;
|
||||
|
||||
# because the program apps/openssl has object files as sources, and
|
||||
# they then have the corresponding C files as source, we need to chain
|
||||
# the lookups in %unified_info
|
||||
my @openssl_source =
|
||||
map { @{$unified_info{sources}->{$_}} }
|
||||
grep { /\.o$/
|
||||
&& !$unified_info{attributes}->{sources}->{$apps_openssl}->{$_}->{nocheck} }
|
||||
@{$unified_info{sources}->{$apps_openssl}};
|
||||
|
||||
foreach my $filename (@openssl_source) {
|
||||
open F, $filename or die "Couldn't open $filename: $!\n";
|
||||
foreach ( grep /$cmdre/, <F> ) {
|
||||
my @foo = /$cmdre/;
|
||||
$commands{$1} = 1;
|
||||
}
|
||||
close F;
|
||||
}
|
||||
|
||||
@ARGV = sort keys %commands;
|
||||
|
||||
if ($opt eq '-H') {
|
||||
print <<"EOF";
|
||||
/*
|
||||
* WARNING: do not edit!
|
||||
* Generated by apps/progs.pl
|
||||
*
|
||||
* Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "function.h"
|
||||
|
||||
EOF
|
||||
|
||||
foreach (@ARGV) {
|
||||
printf "extern int %s_main(int argc, char *argv[]);\n", $_;
|
||||
}
|
||||
print "\n";
|
||||
|
||||
foreach (@ARGV) {
|
||||
printf "extern const OPTIONS %s_options[];\n", $_;
|
||||
}
|
||||
print "\n";
|
||||
print "extern FUNCTION functions[];\n";
|
||||
}
|
||||
|
||||
if ($opt eq '-C') {
|
||||
print <<"EOF";
|
||||
/*
|
||||
* WARNING: do not edit!
|
||||
* Generated by apps/progs.pl
|
||||
*
|
||||
* Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include "progs.h"
|
||||
|
||||
EOF
|
||||
|
||||
my %cmd_disabler = (
|
||||
ciphers => "sock",
|
||||
genrsa => "rsa",
|
||||
gendsa => "dsa",
|
||||
dsaparam => "dsa",
|
||||
gendh => "dh",
|
||||
dhparam => "dh",
|
||||
ecparam => "ec",
|
||||
);
|
||||
my %cmd_deprecated = (
|
||||
# The format of this table is:
|
||||
# [0] = alternative command to use instead
|
||||
# [1] = deprecented in this version
|
||||
# [2] = preprocessor conditional for excluding irrespective of deprecation
|
||||
# rsa => [ "pkey", "3_0", "rsa" ],
|
||||
# genrsa => [ "genpkey", "3_0", "rsa" ],
|
||||
rsautl => [ "pkeyutl", "3_0", "rsa" ],
|
||||
# dhparam => [ "pkeyparam", "3_0", "dh" ],
|
||||
# dsaparam => [ "pkeyparam", "3_0", "dsa" ],
|
||||
# dsa => [ "pkey", "3_0", "dsa" ],
|
||||
# gendsa => [ "genpkey", "3_0", "dsa" ],
|
||||
# ec => [ "pkey", "3_0", "ec" ],
|
||||
# ecparam => [ "pkeyparam", "3_0", "ec" ],
|
||||
);
|
||||
|
||||
print "FUNCTION functions[] = {\n";
|
||||
foreach my $cmd ( @ARGV ) {
|
||||
my $str =
|
||||
" {FT_general, \"$cmd\", ${cmd}_main, ${cmd}_options, NULL, NULL},\n";
|
||||
if ($cmd =~ /^s_/) {
|
||||
print "#ifndef OPENSSL_NO_SOCK\n${str}#endif\n";
|
||||
} elsif (my $deprecated = $cmd_deprecated{$cmd}) {
|
||||
my @dep = @{$deprecated};
|
||||
my $daltprg = $dep[0];
|
||||
my $dver = $dep[1];
|
||||
my $dsys = $dep[2];
|
||||
print "#if !defined(OPENSSL_NO_DEPRECATED_" . $dver . ")";
|
||||
if ($dsys) {
|
||||
print " && !defined(OPENSSL_NO_" . uc($dsys) . ")";
|
||||
}
|
||||
$dver =~ s/_/./g;
|
||||
my $dalt = "\"" . $daltprg . "\", \"" . $dver . "\"";
|
||||
$str =~ s/NULL, NULL/$dalt/;
|
||||
print "\n${str}#endif\n";
|
||||
} elsif (grep { $cmd eq $_ } @disablables) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
|
||||
} elsif (my $disabler = $cmd_disabler{$cmd}) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
|
||||
} else {
|
||||
print $str;
|
||||
}
|
||||
}
|
||||
|
||||
my %md_disabler = (
|
||||
blake2b512 => "blake2",
|
||||
blake2s256 => "blake2",
|
||||
);
|
||||
foreach my $cmd (
|
||||
"md2", "md4", "md5",
|
||||
"sha1", "sha224", "sha256", "sha384",
|
||||
"sha512", "sha512-224", "sha512-256",
|
||||
"sha3-224", "sha3-256", "sha3-384", "sha3-512",
|
||||
"shake128", "shake256",
|
||||
"mdc2", "rmd160", "blake2b512", "blake2s256",
|
||||
"sm3"
|
||||
) {
|
||||
my $str = " {FT_md, \"$cmd\", dgst_main, NULL, NULL},\n";
|
||||
if (grep { $cmd eq $_ } @disablables) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($cmd) . "\n${str}#endif\n";
|
||||
} elsif (my $disabler = $md_disabler{$cmd}) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
|
||||
} else {
|
||||
print $str;
|
||||
}
|
||||
}
|
||||
|
||||
my %cipher_disabler = (
|
||||
des3 => "des",
|
||||
desx => "des",
|
||||
cast5 => "cast",
|
||||
);
|
||||
foreach my $cmd (
|
||||
"aes-128-cbc", "aes-128-ecb",
|
||||
"aes-192-cbc", "aes-192-ecb",
|
||||
"aes-256-cbc", "aes-256-ecb",
|
||||
"aria-128-cbc", "aria-128-cfb",
|
||||
"aria-128-ctr", "aria-128-ecb", "aria-128-ofb",
|
||||
"aria-128-cfb1", "aria-128-cfb8",
|
||||
"aria-192-cbc", "aria-192-cfb",
|
||||
"aria-192-ctr", "aria-192-ecb", "aria-192-ofb",
|
||||
"aria-192-cfb1", "aria-192-cfb8",
|
||||
"aria-256-cbc", "aria-256-cfb",
|
||||
"aria-256-ctr", "aria-256-ecb", "aria-256-ofb",
|
||||
"aria-256-cfb1", "aria-256-cfb8",
|
||||
"camellia-128-cbc", "camellia-128-ecb",
|
||||
"camellia-192-cbc", "camellia-192-ecb",
|
||||
"camellia-256-cbc", "camellia-256-ecb",
|
||||
"base64", "zlib", "brotli", "zstd",
|
||||
"des", "des3", "desx", "idea", "seed", "rc4", "rc4-40",
|
||||
"rc2", "bf", "cast", "rc5",
|
||||
"des-ecb", "des-ede", "des-ede3",
|
||||
"des-cbc", "des-ede-cbc","des-ede3-cbc",
|
||||
"des-cfb", "des-ede-cfb","des-ede3-cfb",
|
||||
"des-ofb", "des-ede-ofb","des-ede3-ofb",
|
||||
"idea-cbc","idea-ecb", "idea-cfb", "idea-ofb",
|
||||
"seed-cbc","seed-ecb", "seed-cfb", "seed-ofb",
|
||||
"rc2-cbc", "rc2-ecb", "rc2-cfb","rc2-ofb", "rc2-64-cbc", "rc2-40-cbc",
|
||||
"bf-cbc", "bf-ecb", "bf-cfb", "bf-ofb",
|
||||
"cast5-cbc","cast5-ecb", "cast5-cfb","cast5-ofb",
|
||||
"cast-cbc", "rc5-cbc", "rc5-ecb", "rc5-cfb", "rc5-ofb",
|
||||
"sm4-cbc", "sm4-ecb", "sm4-cfb", "sm4-ofb", "sm4-ctr"
|
||||
) {
|
||||
my $str = " {FT_cipher, \"$cmd\", enc_main, enc_options, NULL},\n";
|
||||
(my $algo = $cmd) =~ s/-.*//g;
|
||||
if (grep { $algo eq $_ } @disablables) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($algo) . "\n${str}#endif\n";
|
||||
} elsif (my $disabler = $cipher_disabler{$algo}) {
|
||||
print "#ifndef OPENSSL_NO_" . uc($disabler) . "\n${str}#endif\n";
|
||||
} else {
|
||||
print $str;
|
||||
}
|
||||
}
|
||||
|
||||
print " {0, NULL, NULL, NULL, NULL}\n};\n";
|
||||
}
|
||||
200
electron/res/win/openssl/tsget.pl
Executable file
200
electron/res/win/openssl/tsget.pl
Executable file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
|
||||
# Copyright (c) 2002 The OpenTSA Project. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use IO::Handle;
|
||||
use Getopt::Std;
|
||||
use File::Basename;
|
||||
use WWW::Curl::Easy;
|
||||
|
||||
use vars qw(%options);
|
||||
|
||||
# Callback for reading the body.
|
||||
sub read_body {
|
||||
my ($maxlength, $state) = @_;
|
||||
my $return_data = "";
|
||||
my $data_len = length ${$state->{data}};
|
||||
if ($state->{bytes} < $data_len) {
|
||||
$data_len = $data_len - $state->{bytes};
|
||||
$data_len = $maxlength if $data_len > $maxlength;
|
||||
$return_data = substr ${$state->{data}}, $state->{bytes}, $data_len;
|
||||
$state->{bytes} += $data_len;
|
||||
}
|
||||
return $return_data;
|
||||
}
|
||||
|
||||
# Callback for writing the body into a variable.
|
||||
sub write_body {
|
||||
my ($data, $pointer) = @_;
|
||||
${$pointer} .= $data;
|
||||
return length($data);
|
||||
}
|
||||
|
||||
# Initialise a new Curl object.
|
||||
sub create_curl {
|
||||
my $url = shift;
|
||||
|
||||
# Create Curl object.
|
||||
my $curl = WWW::Curl::Easy::new();
|
||||
|
||||
# Error-handling related options.
|
||||
$curl->setopt(CURLOPT_VERBOSE, 1) if $options{d};
|
||||
$curl->setopt(CURLOPT_FAILONERROR, 1);
|
||||
$curl->setopt(CURLOPT_USERAGENT,
|
||||
"OpenTSA tsget.pl/openssl-3.3.1");
|
||||
|
||||
# Options for POST method.
|
||||
$curl->setopt(CURLOPT_UPLOAD, 1);
|
||||
$curl->setopt(CURLOPT_CUSTOMREQUEST, "POST");
|
||||
$curl->setopt(CURLOPT_HTTPHEADER,
|
||||
["Content-Type: application/timestamp-query",
|
||||
"Accept: application/timestamp-reply,application/timestamp-response"]);
|
||||
$curl->setopt(CURLOPT_READFUNCTION, \&read_body);
|
||||
$curl->setopt(CURLOPT_HEADERFUNCTION, sub { return length($_[0]); });
|
||||
|
||||
# Options for getting the result.
|
||||
$curl->setopt(CURLOPT_WRITEFUNCTION, \&write_body);
|
||||
|
||||
# SSL related options.
|
||||
$curl->setopt(CURLOPT_SSLKEYTYPE, "PEM");
|
||||
$curl->setopt(CURLOPT_SSL_VERIFYPEER, 1); # Verify server's certificate.
|
||||
$curl->setopt(CURLOPT_SSL_VERIFYHOST, 2); # Check server's CN.
|
||||
$curl->setopt(CURLOPT_SSLKEY, $options{k}) if defined($options{k});
|
||||
$curl->setopt(CURLOPT_SSLKEYPASSWD, $options{p}) if defined($options{p});
|
||||
$curl->setopt(CURLOPT_SSLCERT, $options{c}) if defined($options{c});
|
||||
$curl->setopt(CURLOPT_CAINFO, $options{C}) if defined($options{C});
|
||||
$curl->setopt(CURLOPT_CAPATH, $options{P}) if defined($options{P});
|
||||
$curl->setopt(CURLOPT_RANDOM_FILE, $options{r}) if defined($options{r});
|
||||
$curl->setopt(CURLOPT_EGDSOCKET, $options{g}) if defined($options{g});
|
||||
|
||||
# Setting destination.
|
||||
$curl->setopt(CURLOPT_URL, $url);
|
||||
|
||||
return $curl;
|
||||
}
|
||||
|
||||
# Send a request and returns the body back.
|
||||
sub get_timestamp {
|
||||
my $curl = shift;
|
||||
my $body = shift;
|
||||
my $ts_body;
|
||||
local $::error_buf;
|
||||
|
||||
# Error-handling related options.
|
||||
$curl->setopt(CURLOPT_ERRORBUFFER, "::error_buf");
|
||||
|
||||
# Options for POST method.
|
||||
$curl->setopt(CURLOPT_INFILE, {data => $body, bytes => 0});
|
||||
$curl->setopt(CURLOPT_INFILESIZE, length(${$body}));
|
||||
|
||||
# Options for getting the result.
|
||||
$curl->setopt(CURLOPT_FILE, \$ts_body);
|
||||
|
||||
# Send the request...
|
||||
my $error_code = $curl->perform();
|
||||
my $error_string;
|
||||
if ($error_code != 0) {
|
||||
my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
|
||||
$error_string = "could not get timestamp";
|
||||
$error_string .= ", http code: $http_code" unless $http_code == 0;
|
||||
$error_string .= ", curl code: $error_code";
|
||||
$error_string .= " ($::error_buf)" if defined($::error_buf);
|
||||
} else {
|
||||
my $ct = $curl->getinfo(CURLINFO_CONTENT_TYPE);
|
||||
if (lc($ct) ne "application/timestamp-reply"
|
||||
&& lc($ct) ne "application/timestamp-response") {
|
||||
$error_string = "unexpected content type returned: $ct";
|
||||
}
|
||||
}
|
||||
return ($ts_body, $error_string);
|
||||
|
||||
}
|
||||
|
||||
# Print usage information and exists.
|
||||
sub usage {
|
||||
|
||||
print STDERR "usage: $0 -h <server_url> [-e <extension>] [-o <output>] ";
|
||||
print STDERR "[-v] [-d] [-k <private_key.pem>] [-p <key_password>] ";
|
||||
print STDERR "[-c <client_cert.pem>] [-C <CA_certs.pem>] [-P <CA_path>] ";
|
||||
print STDERR "[-r <file:file...>] [-g <EGD_socket>] [<request>]...\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Main program
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# Getting command-line options (default comes from TSGET environment variable).
|
||||
my $getopt_arg = "h:e:o:vdk:p:c:C:P:r:g:";
|
||||
if (exists $ENV{TSGET}) {
|
||||
my @old_argv = @ARGV;
|
||||
@ARGV = split /\s+/, $ENV{TSGET};
|
||||
getopts($getopt_arg, \%options) or usage;
|
||||
@ARGV = @old_argv;
|
||||
}
|
||||
getopts($getopt_arg, \%options) or usage;
|
||||
|
||||
# Checking argument consistency.
|
||||
if (!exists($options{h}) || (@ARGV == 0 && !exists($options{o}))
|
||||
|| (@ARGV > 1 && exists($options{o}))) {
|
||||
print STDERR "Inconsistent command line options.\n";
|
||||
usage;
|
||||
}
|
||||
# Setting defaults.
|
||||
@ARGV = ("-") unless @ARGV != 0;
|
||||
$options{e} = ".tsr" unless defined($options{e});
|
||||
|
||||
# Processing requests.
|
||||
my $curl = create_curl $options{h};
|
||||
undef $/; # For reading whole files.
|
||||
REQUEST: foreach (@ARGV) {
|
||||
my $input = $_;
|
||||
my ($base, $path) = fileparse($input, '\.[^.]*');
|
||||
my $output_base = $base . $options{e};
|
||||
my $output = defined($options{o}) ? $options{o} : $path . $output_base;
|
||||
|
||||
STDERR->printflush("$input: ") if $options{v};
|
||||
# Read request.
|
||||
my $body;
|
||||
if ($input eq "-") {
|
||||
# Read the request from STDIN;
|
||||
$body = <STDIN>;
|
||||
} else {
|
||||
# Read the request from file.
|
||||
open INPUT, "<" . $input
|
||||
or warn("$input: could not open input file: $!\n"), next REQUEST;
|
||||
$body = <INPUT>;
|
||||
close INPUT
|
||||
or warn("$input: could not close input file: $!\n"), next REQUEST;
|
||||
}
|
||||
|
||||
# Send request.
|
||||
STDERR->printflush("sending request") if $options{v};
|
||||
|
||||
my ($ts_body, $error) = get_timestamp $curl, \$body;
|
||||
if (defined($error)) {
|
||||
die "$input: fatal error: $error\n";
|
||||
}
|
||||
STDERR->printflush(", reply received") if $options{v};
|
||||
|
||||
# Write response.
|
||||
if ($output eq "-") {
|
||||
# Write to STDOUT.
|
||||
print $ts_body;
|
||||
} else {
|
||||
# Write to file.
|
||||
open OUTPUT, ">", $output
|
||||
or warn("$output: could not open output file: $!\n"), next REQUEST;
|
||||
print OUTPUT $ts_body;
|
||||
close OUTPUT
|
||||
or warn("$output: could not close output file: $!\n"), next REQUEST;
|
||||
}
|
||||
STDERR->printflush(", $output written.\n") if $options{v};
|
||||
}
|
||||
$curl->cleanup();
|
||||
0
electron/res/regedit-vbs/1.wsf → electron/res/win/regedit-vbs/1.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/1.wsf → electron/res/win/regedit-vbs/1.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/ArchitectureAgnosticRegistry.vbs → electron/res/win/regedit-vbs/ArchitectureAgnosticRegistry.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/ArchitectureAgnosticRegistry.vbs → electron/res/win/regedit-vbs/ArchitectureAgnosticRegistry.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/ArchitectureSpecificRegistry.vbs → electron/res/win/regedit-vbs/ArchitectureSpecificRegistry.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/ArchitectureSpecificRegistry.vbs → electron/res/win/regedit-vbs/ArchitectureSpecificRegistry.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/JsonSafeTest.wsf → electron/res/win/regedit-vbs/JsonSafeTest.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/JsonSafeTest.wsf → electron/res/win/regedit-vbs/JsonSafeTest.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regCreateKey.wsf → electron/res/win/regedit-vbs/regCreateKey.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regCreateKey.wsf → electron/res/win/regedit-vbs/regCreateKey.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regDeleteKey.wsf → electron/res/win/regedit-vbs/regDeleteKey.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regDeleteKey.wsf → electron/res/win/regedit-vbs/regDeleteKey.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regDeleteValue.wsf → electron/res/win/regedit-vbs/regDeleteValue.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regDeleteValue.wsf → electron/res/win/regedit-vbs/regDeleteValue.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regList.wsf → electron/res/win/regedit-vbs/regList.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regList.wsf → electron/res/win/regedit-vbs/regList.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regListStream.wsf → electron/res/win/regedit-vbs/regListStream.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regListStream.wsf → electron/res/win/regedit-vbs/regListStream.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regPutValue.wsf → electron/res/win/regedit-vbs/regPutValue.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regPutValue.wsf → electron/res/win/regedit-vbs/regPutValue.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/regUtil.vbs → electron/res/win/regedit-vbs/regUtil.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/regUtil.vbs → electron/res/win/regedit-vbs/regUtil.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/util.vbs → electron/res/win/regedit-vbs/util.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/util.vbs → electron/res/win/regedit-vbs/util.vbs
Executable file → Normal file
0
electron/res/regedit-vbs/wsRegReadList.wsf → electron/res/win/regedit-vbs/wsRegReadList.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/wsRegReadList.wsf → electron/res/win/regedit-vbs/wsRegReadList.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/wsRegReadListStream.wsf → electron/res/win/regedit-vbs/wsRegReadListStream.wsf
Executable file → Normal file
0
electron/res/regedit-vbs/wsRegReadListStream.wsf → electron/res/win/regedit-vbs/wsRegReadListStream.wsf
Executable file → Normal file
BIN
electron/res/win/w_c.exe
Normal file
BIN
electron/res/win/w_c.exe
Normal file
Binary file not shown.
4745
electron/wxjs/decrypt.js
Executable file
4745
electron/wxjs/decrypt.js
Executable file
File diff suppressed because one or more lines are too long
10
index.html
10
index.html
@@ -1,11 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
|
||||
<title>资源下载器</title>
|
||||
<meta charset="UTF-8"/>
|
||||
<link rel="icon" href="/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';"/>
|
||||
<title>爱享素材下载器</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
616
override/hoxy/lib/cycle.js
Normal file
616
override/hoxy/lib/cycle.js
Normal file
@@ -0,0 +1,616 @@
|
||||
/*
|
||||
* Copyright (c) 2015 by Greg Reimer <gregreimer@gmail.com>
|
||||
* MIT License. See mit-license.txt for more info.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var _createClass = require('babel-runtime/helpers/create-class')['default'];
|
||||
|
||||
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
|
||||
|
||||
var _get = require('babel-runtime/helpers/get')['default'];
|
||||
|
||||
var _inherits = require('babel-runtime/helpers/inherits')['default'];
|
||||
|
||||
var _Promise = require('babel-runtime/core-js/promise')['default'];
|
||||
|
||||
var _regeneratorRuntime = require('babel-runtime/regenerator')['default'];
|
||||
|
||||
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _request = require('./request');
|
||||
|
||||
var _request2 = _interopRequireDefault(_request);
|
||||
|
||||
var _response = require('./response');
|
||||
|
||||
var _response2 = _interopRequireDefault(_response);
|
||||
|
||||
var _streams = require('./streams');
|
||||
|
||||
var _streams2 = _interopRequireDefault(_streams);
|
||||
|
||||
var _await = require('await');
|
||||
|
||||
var _await2 = _interopRequireDefault(_await);
|
||||
|
||||
var _mkdirp = require('mkdirp');
|
||||
|
||||
var _mkdirp2 = _interopRequireDefault(_mkdirp);
|
||||
|
||||
var _lodash = require('lodash');
|
||||
|
||||
var _lodash2 = _interopRequireDefault(_lodash);
|
||||
|
||||
var _nodeStatic = require('node-static');
|
||||
|
||||
var _http = require('http');
|
||||
|
||||
var _http2 = _interopRequireDefault(_http);
|
||||
|
||||
var _https = require('https');
|
||||
|
||||
var _https2 = _interopRequireDefault(_https);
|
||||
|
||||
var _url = require('url');
|
||||
|
||||
var _url2 = _interopRequireDefault(_url);
|
||||
|
||||
var _fs = require('fs');
|
||||
|
||||
var _fs2 = _interopRequireDefault(_fs);
|
||||
|
||||
var _util = require('util');
|
||||
|
||||
var _util2 = _interopRequireDefault(_util);
|
||||
|
||||
var _path = require('path');
|
||||
|
||||
var _path2 = _interopRequireDefault(_path);
|
||||
|
||||
var _zlib = require('zlib');
|
||||
|
||||
var _zlib2 = _interopRequireDefault(_zlib);
|
||||
|
||||
var _events = require('events');
|
||||
|
||||
var _co = require('co');
|
||||
|
||||
var _co2 = _interopRequireDefault(_co);
|
||||
|
||||
var _uglyAdapter = require('ugly-adapter');
|
||||
|
||||
var _uglyAdapter2 = _interopRequireDefault(_uglyAdapter);
|
||||
|
||||
var _wait = require('./wait');
|
||||
|
||||
var _wait2 = _interopRequireDefault(_wait);
|
||||
|
||||
var _task = require('./task');
|
||||
|
||||
var _task2 = _interopRequireDefault(_task);
|
||||
|
||||
var _urlPath = require('./url-path');
|
||||
const url = require("url");
|
||||
|
||||
var _urlPath2 = _interopRequireDefault(_urlPath);
|
||||
|
||||
var staticServer = (function () {
|
||||
|
||||
var getStatic = (function () {
|
||||
var statics = {};
|
||||
return function (docroot) {
|
||||
var stat = statics[docroot];
|
||||
if (!stat) {
|
||||
stat = statics[docroot] = new _nodeStatic.Server(docroot);
|
||||
}
|
||||
return stat;
|
||||
};
|
||||
})();
|
||||
|
||||
// Start up the server and serve out of various docroots.
|
||||
var server = _http2['default'].createServer(function (req, resp) {
|
||||
var docroot = req.headers['x-hoxy-static-docroot'];
|
||||
var pDocroot = new _urlPath2['default'](docroot);
|
||||
var stat = getStatic(pDocroot.toSystemPath());
|
||||
stat.serve(req, resp);
|
||||
}).listen(0, 'localhost');
|
||||
|
||||
return server;
|
||||
})();
|
||||
|
||||
var httpsOverHttpAgent, httpsOverHttpsAgent, httpOverHttpsAgent;
|
||||
var tunnelAgent = require('tunnel-agent');
|
||||
var ptGetTunnelAgent = function (requestIsSSL, externalProxyUrl) {
|
||||
var urlObject = url.parse(externalProxyUrl);
|
||||
var protocol = urlObject.protocol || 'http:';
|
||||
var port = urlObject.port;
|
||||
if (!port) {
|
||||
port = protocol === 'http:' ? 80 : 443;
|
||||
}
|
||||
var hostname = urlObject.hostname || 'localhost';
|
||||
|
||||
if (requestIsSSL) {
|
||||
if (protocol === 'http:') {
|
||||
if (!httpsOverHttpAgent) {
|
||||
httpsOverHttpAgent = tunnelAgent.httpsOverHttp({
|
||||
proxy: {
|
||||
host: hostname,
|
||||
port: port
|
||||
}
|
||||
});
|
||||
}
|
||||
return httpsOverHttpAgent;
|
||||
} else {
|
||||
if (!httpsOverHttpsAgent) {
|
||||
httpsOverHttpsAgent = tunnelAgent.httpsOverHttps({
|
||||
proxy: {
|
||||
host: hostname,
|
||||
port: port
|
||||
}
|
||||
});
|
||||
}
|
||||
return httpsOverHttpsAgent;
|
||||
}
|
||||
} else {
|
||||
if (protocol === 'http:') {
|
||||
// if (!httpOverHttpAgent) {
|
||||
// httpOverHttpAgent = tunnelAgent.httpOverHttp({
|
||||
// proxy: {
|
||||
// host: hostname,
|
||||
// port: port
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
return false;
|
||||
} else {
|
||||
if (!httpOverHttpsAgent) {
|
||||
httpOverHttpsAgent = tunnelAgent.httpOverHttps({
|
||||
proxy: {
|
||||
host: hostname,
|
||||
port: port
|
||||
}
|
||||
});
|
||||
}
|
||||
return httpOverHttpsAgent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var ProvisionableRequest = (function () {
|
||||
function ProvisionableRequest(opts) {
|
||||
_classCallCheck(this, ProvisionableRequest);
|
||||
|
||||
this._respProm = (0, _task2['default'])();
|
||||
var h = /https/i.test(opts.protocol) ? _https2['default'] : _http2['default'];
|
||||
if (opts.proxy) {
|
||||
// var proxyInfo = _url2['default'].parse(opts.proxy),
|
||||
// proxyPort = proxyInfo.port,
|
||||
// proxyHostname = proxyInfo.hostname,
|
||||
// proxyPath = 'http://' + opts.hostname + (opts.port ? ':' + opts.port : '') + opts.path;
|
||||
// opts.hostname = proxyHostname;
|
||||
// opts.port = proxyPort;
|
||||
// opts.path = proxyPath;
|
||||
opts.agent = ptGetTunnelAgent(/https/i.test(opts.protocol), opts.proxy);
|
||||
// console.log('opts.agent', opts.proxy)
|
||||
opts.proxy = ''
|
||||
}
|
||||
|
||||
this._writable = h.request(opts, this._respProm.resolve);
|
||||
this._writable.on('error', this._respProm.reject);
|
||||
}
|
||||
|
||||
/*
|
||||
* This check() function made me scratch my head when I came back to
|
||||
* it months later. It simply does too many things. It still isn't perfect,
|
||||
* but hopefully now this beast is slightly easier to follow. It returns
|
||||
* a promise on a boolean indicating whether or not the passed file was
|
||||
* created. IF the strategy is NOT 'mirror' it resolves false since 'mirror'
|
||||
* is the only strategy that creates files. Otherwise if the file exists
|
||||
* it resolves false. Otherwise it has a side effect of creating the file
|
||||
* by requesting out to the remote server and writing the result to the
|
||||
* file, then resolves true.
|
||||
*/
|
||||
|
||||
_createClass(ProvisionableRequest, [{
|
||||
key: 'send',
|
||||
value: function send(readable) {
|
||||
var _this = this;
|
||||
|
||||
return new _Promise(function (resolve, reject) {
|
||||
if (!readable || typeof readable === 'string') {
|
||||
_this._writable.end(readable || '', resolve);
|
||||
} else {
|
||||
readable.on('error', reject);
|
||||
readable.on('end', resolve);
|
||||
readable.pipe(_this._writable);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'receive',
|
||||
value: function receive() {
|
||||
return this._respProm;
|
||||
}
|
||||
}]);
|
||||
|
||||
return ProvisionableRequest;
|
||||
})();
|
||||
|
||||
function check(strategy, file, req, upstreamProxy) {
|
||||
var parsed = _url2['default'].parse(file);
|
||||
file = parsed.pathname; // stripped of query string.
|
||||
|
||||
return (0, _co2['default'])(_regeneratorRuntime.mark(function callee$1$0() {
|
||||
var provReq, mirrResp, writeToFile, gunzip;
|
||||
return _regeneratorRuntime.wrap(function callee$1$0$(context$2$0) {
|
||||
while (1) switch (context$2$0.prev = context$2$0.next) {
|
||||
case 0:
|
||||
if (!(strategy !== 'mirror')) {
|
||||
context$2$0.next = 2;
|
||||
break;
|
||||
}
|
||||
|
||||
return context$2$0.abrupt('return', false);
|
||||
|
||||
case 2:
|
||||
context$2$0.prev = 2;
|
||||
context$2$0.next = 5;
|
||||
return (0, _uglyAdapter2['default'])(_fs2['default'].stat, file);
|
||||
|
||||
case 5:
|
||||
return context$2$0.abrupt('return', false);
|
||||
|
||||
case 8:
|
||||
context$2$0.prev = 8;
|
||||
context$2$0.t0 = context$2$0['catch'](2);
|
||||
|
||||
case 10:
|
||||
context$2$0.next = 12;
|
||||
return (0, _uglyAdapter2['default'])(_mkdirp2['default'], _path2['default'].dirname(file));
|
||||
|
||||
case 12:
|
||||
provReq = new ProvisionableRequest({
|
||||
protocol: req.protocol,
|
||||
proxy: upstreamProxy,
|
||||
method: 'GET',
|
||||
hostname: req.hostname,
|
||||
port: req.port,
|
||||
path: req.url
|
||||
});
|
||||
|
||||
provReq.send();
|
||||
context$2$0.next = 16;
|
||||
return provReq.receive();
|
||||
|
||||
case 16:
|
||||
mirrResp = context$2$0.sent;
|
||||
|
||||
if (!(mirrResp.statusCode !== 200)) {
|
||||
context$2$0.next = 19;
|
||||
break;
|
||||
}
|
||||
|
||||
throw new Error('mirroring failed: ' + req.fullUrl() + ' => ' + mirrResp.statusCode);
|
||||
|
||||
case 19:
|
||||
writeToFile = _fs2['default'].createWriteStream(file);
|
||||
|
||||
if (mirrResp.headers['content-encoding'] === 'gzip') {
|
||||
gunzip = _zlib2['default'].createGunzip();
|
||||
|
||||
mirrResp = mirrResp.pipe(gunzip);
|
||||
}
|
||||
context$2$0.next = 23;
|
||||
return new _Promise(function (resolve, reject) {
|
||||
mirrResp.pipe(writeToFile);
|
||||
mirrResp.on('end', resolve);
|
||||
writeToFile.on('error', reject);
|
||||
});
|
||||
|
||||
case 23:
|
||||
case 'end':
|
||||
return context$2$0.stop();
|
||||
}
|
||||
}, callee$1$0, this, [[2, 8]]);
|
||||
}));
|
||||
}
|
||||
|
||||
// ---------------------------
|
||||
|
||||
var Cycle = (function (_EventEmitter) {
|
||||
_inherits(Cycle, _EventEmitter);
|
||||
|
||||
function Cycle(proxy) {
|
||||
var _this2 = this;
|
||||
|
||||
_classCallCheck(this, Cycle);
|
||||
|
||||
_get(Object.getPrototypeOf(Cycle.prototype), 'constructor', this).call(this);
|
||||
this._proxy = proxy;
|
||||
this._request = new _request2['default']();
|
||||
this._response = new _response2['default']();
|
||||
this._request.on('log', function (log) {
|
||||
return _this2.emit('log', log);
|
||||
});
|
||||
this._response.on('log', function (log) {
|
||||
return _this2.emit('log', log);
|
||||
});
|
||||
}
|
||||
|
||||
_createClass(Cycle, [{
|
||||
key: 'data',
|
||||
value: function data(name, val) {
|
||||
if (!this._userData) {
|
||||
this._userData = {};
|
||||
}
|
||||
if (arguments.length === 2) {
|
||||
this._userData[name] = val;
|
||||
}
|
||||
return this._userData[name];
|
||||
}
|
||||
}, {
|
||||
key: 'serve',
|
||||
value: function serve(opts) {
|
||||
|
||||
return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() {
|
||||
var req, resp, _opts, docroot, path, strategy, headers, pDocroot, pPath, pFullPath, fullSysPath,
|
||||
created, staticResp, code, useResponse, isError, message;
|
||||
|
||||
return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
|
||||
while (1) switch (context$3$0.prev = context$3$0.next) {
|
||||
case 0:
|
||||
req = this._request;
|
||||
resp = this._response;
|
||||
|
||||
if (typeof opts === 'string') {
|
||||
opts = {path: opts};
|
||||
}
|
||||
opts = _lodash2['default'].extend({
|
||||
docroot: _path2['default'].sep,
|
||||
path: _url2['default'].parse(req.url).pathname,
|
||||
strategy: 'replace'
|
||||
}, opts);
|
||||
_opts = opts;
|
||||
docroot = _opts.docroot;
|
||||
path = _opts.path;
|
||||
strategy = _opts.strategy;
|
||||
headers = _lodash2['default'].extend({
|
||||
'x-hoxy-static-docroot': docroot
|
||||
}, req.headers);
|
||||
|
||||
delete headers['if-none-match'];
|
||||
delete headers['if-modified-since'];
|
||||
|
||||
// Now call the static file service.
|
||||
pDocroot = new _urlPath2['default'](docroot), pPath = new _urlPath2['default'](path), pFullPath = pPath.rootTo(pDocroot), fullSysPath = pFullPath.toSystemPath();
|
||||
context$3$0.next = 14;
|
||||
return check(strategy, fullSysPath, req, this._proxy._upstreamProxy);
|
||||
|
||||
case 14:
|
||||
created = context$3$0.sent;
|
||||
|
||||
if (created) {
|
||||
this.emit('log', {
|
||||
level: 'info',
|
||||
message: 'copied ' + req.fullUrl() + ' to ' + fullSysPath
|
||||
});
|
||||
}
|
||||
context$3$0.next = 18;
|
||||
return new _Promise(function (resolve, reject) {
|
||||
var addr = staticServer.address();
|
||||
_http2['default'].get({
|
||||
hostname: addr.address,
|
||||
port: addr.port,
|
||||
headers: headers,
|
||||
path: pPath.toUrlPath()
|
||||
}, resolve).on('error', reject);
|
||||
});
|
||||
|
||||
case 18:
|
||||
staticResp = context$3$0.sent;
|
||||
code = staticResp.statusCode, useResponse = undefined, isError = undefined;
|
||||
|
||||
if (/^2\d\d$/.test(code)) {
|
||||
useResponse = true;
|
||||
} else if (/^4\d\d$/.test(code)) {
|
||||
if (strategy === 'replace') {
|
||||
useResponse = true;
|
||||
} else if (strategy === 'mirror') {
|
||||
isError = true;
|
||||
}
|
||||
} else {
|
||||
isError = true; // nope
|
||||
}
|
||||
|
||||
if (!isError) {
|
||||
context$3$0.next = 26;
|
||||
break;
|
||||
}
|
||||
|
||||
message = _util2['default'].format('Failed to serve static file: %s => %s. Static server returned %d. Strategy: %s', req.fullUrl(), fullSysPath, staticResp.statusCode, strategy);
|
||||
throw new Error(message);
|
||||
|
||||
case 26:
|
||||
if (useResponse) {
|
||||
resp._setHttpSource(staticResp);
|
||||
}
|
||||
|
||||
case 27:
|
||||
case 'end':
|
||||
return context$3$0.stop();
|
||||
}
|
||||
}, callee$2$0, this);
|
||||
}));
|
||||
}
|
||||
}, {
|
||||
key: '_setPhase',
|
||||
value: function _setPhase(phase) {
|
||||
this._phase = this._request.phase = this._response.phase = phase;
|
||||
}
|
||||
|
||||
/*
|
||||
* This returns a promise on a partially fulfilled request
|
||||
* (an instance of class ProvisionableRequest). At the time
|
||||
* the promise is fulfilled, the request is in a state where
|
||||
* it's been fully piped out, but nothing received. It's up
|
||||
* to the caller of this function to call receive() on it, thus
|
||||
* getting a promise on the serverResponse object. That enables
|
||||
* hoxy to implement the 'request-sent' phase.
|
||||
*/
|
||||
}, {
|
||||
key: '_sendToServer',
|
||||
value: function _sendToServer() {
|
||||
var req = this._request._finalize(),
|
||||
resp = this._response,
|
||||
upstreamProxy = this._proxy._upstreamProxy,
|
||||
source = req._source,
|
||||
pSlow = this._proxy._slow || {},
|
||||
rSlow = req.slow() || {},
|
||||
latency = rSlow.latency || 0;
|
||||
if (resp._populated) {
|
||||
return _Promise.resolve(undefined);
|
||||
}
|
||||
return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() {
|
||||
var provisionableReq, brake, groupedBrake;
|
||||
return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
|
||||
while (1) switch (context$3$0.prev = context$3$0.next) {
|
||||
case 0:
|
||||
provisionableReq = new ProvisionableRequest({
|
||||
protocol: req.protocol,
|
||||
proxy: upstreamProxy,
|
||||
hostname: req.hostname,
|
||||
port: req.port || req._getDefaultPort(),
|
||||
method: req.method,
|
||||
path: req.url,
|
||||
headers: req.headers
|
||||
});
|
||||
|
||||
if (!(latency > 0)) {
|
||||
context$3$0.next = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
context$3$0.next = 4;
|
||||
return (0, _wait2['default'])(latency);
|
||||
|
||||
case 4:
|
||||
if (rSlow.rate > 0) {
|
||||
brake = _streams2['default'].brake(rSlow.rate);
|
||||
|
||||
source = source.pipe(brake);
|
||||
}
|
||||
if (pSlow.rate) {
|
||||
groupedBrake = pSlow.rate.throttle();
|
||||
|
||||
source = source.pipe(groupedBrake);
|
||||
}
|
||||
if (pSlow.up) {
|
||||
groupedBrake = pSlow.up.throttle();
|
||||
|
||||
source = source.pipe(groupedBrake);
|
||||
}
|
||||
req._tees().forEach(function (writable) {
|
||||
return source.pipe(writable);
|
||||
});
|
||||
context$3$0.next = 10;
|
||||
return provisionableReq.send(source);
|
||||
|
||||
case 10:
|
||||
return context$3$0.abrupt('return', provisionableReq);
|
||||
|
||||
case 11:
|
||||
case 'end':
|
||||
return context$3$0.stop();
|
||||
}
|
||||
}, callee$2$0, this);
|
||||
}));
|
||||
}
|
||||
}, {
|
||||
key: '_sendToClient',
|
||||
value: function _sendToClient(outResp) {
|
||||
var resp = this._response._finalize(),
|
||||
source = resp._source,
|
||||
rSlow = resp.slow() || {},
|
||||
pSlow = this._proxy._slow || {},
|
||||
rLatency = rSlow.latency || 0,
|
||||
pLatency = pSlow.latency || 0,
|
||||
latency = Math.max(pLatency, rLatency);
|
||||
return _co2['default'].call(this, _regeneratorRuntime.mark(function callee$2$0() {
|
||||
var brake, groupedBrake, tees;
|
||||
return _regeneratorRuntime.wrap(function callee$2$0$(context$3$0) {
|
||||
while (1) switch (context$3$0.prev = context$3$0.next) {
|
||||
case 0:
|
||||
if (!(latency > 0)) {
|
||||
context$3$0.next = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
context$3$0.next = 3;
|
||||
return (0, _wait2['default'])(latency);
|
||||
|
||||
case 3:
|
||||
outResp.writeHead(resp.statusCode, resp.headers);
|
||||
if (rSlow.rate > 0) {
|
||||
brake = _streams2['default'].brake(rSlow.rate);
|
||||
|
||||
source = source.pipe(brake);
|
||||
}
|
||||
if (pSlow.rate) {
|
||||
groupedBrake = pSlow.rate.throttle();
|
||||
|
||||
source = source.pipe(groupedBrake);
|
||||
}
|
||||
if (pSlow.down) {
|
||||
groupedBrake = pSlow.down.throttle();
|
||||
|
||||
source = source.pipe(groupedBrake);
|
||||
}
|
||||
tees = resp._tees();
|
||||
|
||||
tees.forEach(function (writable) {
|
||||
return source.pipe(writable);
|
||||
});
|
||||
context$3$0.next = 11;
|
||||
return new _Promise(function (resolve, reject) {
|
||||
source.on('error', reject);
|
||||
source.on('end', resolve);
|
||||
source.pipe(outResp);
|
||||
});
|
||||
|
||||
case 11:
|
||||
case 'end':
|
||||
return context$3$0.stop();
|
||||
}
|
||||
}, callee$2$0, this);
|
||||
}));
|
||||
}
|
||||
}, {
|
||||
key: '_start',
|
||||
value: function _start() {
|
||||
// for now, an immediately-kept promise
|
||||
return (0, _await2['default'])('started').keep('started');
|
||||
}
|
||||
}]);
|
||||
|
||||
return Cycle;
|
||||
})(_events.EventEmitter);
|
||||
|
||||
exports['default'] = Cycle;
|
||||
module.exports = exports['default'];
|
||||
|
||||
// file does not exist, so continue
|
||||
|
||||
// TODO: test coverage for mkdirp
|
||||
|
||||
// TODO: test coverage
|
||||
|
||||
// First, get all our ducks in a row WRT to
|
||||
// options, setting variables, etc.
|
||||
// return the outer promise
|
||||
// wait for it all to pipe out
|
||||
21
package.json
21
package.json
@@ -1,9 +1,13 @@
|
||||
{
|
||||
"name": "res-downloader",
|
||||
"version": "1.0.2",
|
||||
"version": "2.1.2",
|
||||
"main": "dist-electron/main/index.js",
|
||||
"description": "Electron + Vue + Vite 实现的资源下载软件,支持微信视频号下载、抖音视频下载、快手视频下载、酷狗音乐下载等",
|
||||
"author": "putyy@qq.com",
|
||||
"description": "res-downloader(爱享素材下载器),支持视频号、小程序、抖音、快手、小红书、酷狗音乐、qq音乐、qq短视频等",
|
||||
"homepage": "https://github.com/putyy/res-downloader",
|
||||
"author": {
|
||||
"name": "putyy",
|
||||
"email": "putyy@qq.com"
|
||||
},
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"keywords": [
|
||||
@@ -19,8 +23,8 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vue-tsc --noEmit && vite build && electron-builder",
|
||||
"dev": "node script/hoxy.ts && vite",
|
||||
"build": "node script/hoxy.ts && vue-tsc --noEmit && vite build && electron-builder",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -50,12 +54,11 @@
|
||||
"vite-plugin-electron-renderer": "^0.14.5",
|
||||
"vue": "^3.3.4",
|
||||
"vue-router": "^4.2.4",
|
||||
"vue-tsc": "^1.8.8"
|
||||
"vue-tsc": "^2.0.29"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.5.0",
|
||||
"electron-store": "^8.1.0",
|
||||
"getmac": "^5.20.0",
|
||||
"hoxy": "^3.3.1"
|
||||
"hoxy": "^3.3.1",
|
||||
"tunnel-agent": "^0.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/show.png
BIN
public/show.png
Binary file not shown.
|
Before Width: | Height: | Size: 125 KiB |
BIN
public/show.webp
Normal file
BIN
public/show.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
7
script/hoxy.ts
Normal file
7
script/hoxy.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const currentDir = process.cwd();
|
||||
|
||||
// 移动文件
|
||||
fs.copyFile(currentDir + '/override/hoxy/lib/cycle.js', currentDir + '/node_modules/hoxy/lib/cycle.js', fs.constants.COPYFILE_FICLONE, (err) => {
|
||||
});
|
||||
@@ -2,39 +2,17 @@
|
||||
import {ipcRenderer} from 'electron'
|
||||
import pkg from '../../../package.json'
|
||||
const v = pkg.version
|
||||
const jump = (scene: number)=>{
|
||||
switch (scene) {
|
||||
case 1:
|
||||
ipcRenderer.invoke('invoke_open_default_browser', {
|
||||
url: "https://github.com/putyy/res-downloader"
|
||||
})
|
||||
break;
|
||||
case 2:
|
||||
ipcRenderer.invoke('invoke_open_default_browser', {
|
||||
url: "https://s.gowas.cn"
|
||||
})
|
||||
break;
|
||||
case 3:
|
||||
ipcRenderer.invoke('invoke_open_default_browser', {
|
||||
url: "https://i.gowas.cn"
|
||||
})
|
||||
break;
|
||||
case 4:
|
||||
ipcRenderer.invoke('invoke_open_default_browser', {
|
||||
url: "https://github.com/putyy/res-downloader/issues"
|
||||
})
|
||||
break;
|
||||
}
|
||||
const jump = (url: string)=>{
|
||||
ipcRenderer.invoke('invoke_open_default_browser', {
|
||||
url: url
|
||||
})
|
||||
}
|
||||
</script>
|
||||
<template lang="pug">
|
||||
div.line
|
||||
a.item 当前版本: {{v}}
|
||||
a.item 站长邮箱: putyy@qq.com
|
||||
a.item(@click="jump(1)") 获取更新
|
||||
a.item(@click="jump(2)") 云盘资源
|
||||
a.item(@click="jump(3)") chatgpt
|
||||
a.item(@click="jump(4)") 问题反馈
|
||||
a.item(@click="jump('https://s.gowas.cn/d/4089-quan-ping-tai-zi-yuan-xia-zai-ruan-jian')") 获取更新&问题反馈
|
||||
a.item(@click="jump('https://github.com/putyy/res-downloader')") 软件源码
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -42,6 +20,7 @@ div.line
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
.item{
|
||||
padding: 0 5px;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -12,9 +12,12 @@ el-container
|
||||
Sidebar
|
||||
el-container
|
||||
el-main
|
||||
router-view
|
||||
el-footer
|
||||
Footer
|
||||
router-view(v-slot="{ Component, route }")
|
||||
keep-alive(v-if="route.meta.keepAlive")
|
||||
component(:is="Component")
|
||||
component(v-else :is="Component")
|
||||
el-footer
|
||||
Footer
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@@ -24,4 +27,9 @@ el-container
|
||||
.el-main {
|
||||
text-align: center;
|
||||
}
|
||||
.el-footer{
|
||||
margin: unset !important;
|
||||
padding: unset !important;
|
||||
height: auto !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script setup lang="ts">
|
||||
import {inject, onMounted, ref, watch} from 'vue'
|
||||
import localStorageCache from "../../common/localStorage";
|
||||
import localStorageCache from "../../common/localStorage"
|
||||
|
||||
const appName = "资源下载器"
|
||||
const appName = "爱享素材"
|
||||
const sidebarCollapse = ref(inject('sidebarCollapse'))
|
||||
const defaultActive = ref("/index")
|
||||
|
||||
@@ -20,11 +20,7 @@ div.sidebar
|
||||
el-menu-item(key="1" index="/index")
|
||||
el-icon
|
||||
VideoCamera
|
||||
span 拦截下载
|
||||
el-menu-item(key="7" index="/vip-parse")
|
||||
el-icon
|
||||
VideoCamera
|
||||
span 影视解析
|
||||
span 嗅探
|
||||
el-menu-item(key="2" index="/about")
|
||||
el-icon
|
||||
Share
|
||||
|
||||
@@ -13,23 +13,21 @@ const routes = [
|
||||
{
|
||||
path: '/index',
|
||||
name: 'Index',
|
||||
meta: {keepAlive: true},
|
||||
component: () => import('./views/Index.vue'),
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
meta: {keepAlive: true},
|
||||
component: () => import('./views/About.vue'),
|
||||
},
|
||||
{
|
||||
path: '/setting',
|
||||
name: 'Setting',
|
||||
meta: {keepAlive: true},
|
||||
component: () => import('./views/Setting.vue'),
|
||||
},
|
||||
{
|
||||
path: '/vip-parse',
|
||||
name: 'VipParse',
|
||||
component: () => import('./views/VipParse.vue'),
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -24,10 +24,31 @@ const jump = (scene: number)=>{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const str = "使用方法\n" +
|
||||
" 1. 打开本软件\n" +
|
||||
" 2. 软件首页选择要获取的资源类型(默认选中的视频)\n" +
|
||||
" 3. 打开要捕获的源, 如:视频号、网页、小程序等等\n" +
|
||||
" 4. 返回软件首页即可看到要下载的资源\n" +
|
||||
" 5. 直播流复制的链接如何使用?可以使用obs或者ffmpeg命令\n" +
|
||||
"常见问题\n" +
|
||||
" 1. 无法拦截获取\n" +
|
||||
" 手动检测系统代理是否设置正确 本软件代理地址: 127.0.0.1:8899\n" +
|
||||
" 2. 关闭软件后无法正常上网\n" +
|
||||
" 手动关闭系统代理设置\n" +
|
||||
" 3. 视频号抓取流程\n" +
|
||||
" 将需要下载的视频发给好友或者文件助手 再打开该视频即可拦截到,通常软件界面对应视频会出现标题描述、对应操作会出现解密下载按钮\n" +
|
||||
" 大视频可以复制链接通过其他工具加速下载,然后再通过对应的视频操作项进行\"视频解密\"\n" +
|
||||
|
||||
"实现原理\n" +
|
||||
" 通过代理网络抓包拦截响应,筛选出有用的资源,\n" +
|
||||
" 同fiddler、charles等抓包软件、浏览器F12打开控制也能达到目的,\n" +
|
||||
" 只不过这些软件需要手动进行筛选,对于小白用户上手还是有点难度,本软件对部分资源做了特殊处理,\n" +
|
||||
" 更适合大众用户,所以就有了本项目这样的软件。\n"
|
||||
</script>
|
||||
<template lang="pug">
|
||||
div.about
|
||||
div 1. 本软件免费、源代码已经开源,不会以任何形式收取费用。
|
||||
div 1. 本软件免费、代码已开源,不会以任何形式收取费用。
|
||||
el-button(@click="jump(3)") 查看源码
|
||||
div 2. m3u8复制的链接如何使用?
|
||||
el-button(@click="jump(1)") 在线下载
|
||||
@@ -36,6 +57,8 @@ div.about
|
||||
el-button(@click="jump(3)") 获取更新
|
||||
div 4. 问题反馈
|
||||
el-button(@click="jump(4)") 点击前往
|
||||
div.more {{str}}
|
||||
|
||||
</template>
|
||||
|
||||
<style lang="less">
|
||||
@@ -50,5 +73,10 @@ div.about
|
||||
padding: .3rem;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.more{
|
||||
width: 100%; /* 设置容器宽度 */
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word; /* 允许在单词边界内换行 */
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,39 +1,70 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, onMounted} from "vue"
|
||||
import {ref, onMounted, onUnmounted, watch} from "vue"
|
||||
import {ipcRenderer} from 'electron'
|
||||
import {onUnmounted} from "@vue/runtime-core"
|
||||
import {ElMessage, ElLoading, ElTable} from "element-plus"
|
||||
import localStorageCache from "../common/localStorage"
|
||||
import {Delete, Promotion} from "@element-plus/icons-vue"
|
||||
|
||||
interface resData {
|
||||
url_sign: string,
|
||||
url: string,
|
||||
url_sign: string,
|
||||
size: any,
|
||||
platform: string,
|
||||
type: string,
|
||||
type_str: string,
|
||||
progress_bar: any,
|
||||
save_path: string,
|
||||
downing: boolean
|
||||
decode_key: string,
|
||||
description: string,
|
||||
}
|
||||
|
||||
const tableData = ref<resData[]>([])
|
||||
|
||||
const resType = ref({
|
||||
video: true,
|
||||
audio: true,
|
||||
image: false,
|
||||
m3u8: false
|
||||
})
|
||||
|
||||
|
||||
const isInitApp = ref(false)
|
||||
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
const multipleSelection = ref<resData[]>([])
|
||||
const loading = ref()
|
||||
const resType = ref(["all"])
|
||||
const typeOptions = ref([
|
||||
{
|
||||
value: "all",
|
||||
label: "全部",
|
||||
},
|
||||
{
|
||||
value: "image",
|
||||
label: "图片",
|
||||
}, {
|
||||
value: "audio",
|
||||
label: "音频"
|
||||
}, {
|
||||
value: "video",
|
||||
label: "视频"
|
||||
}, {
|
||||
value: "m3u8",
|
||||
label: "m3u8"
|
||||
}, {
|
||||
value: "live",
|
||||
label: "直播流"
|
||||
}, {
|
||||
value: "xls",
|
||||
label: "文档"
|
||||
}, {
|
||||
value: "doc",
|
||||
label: "doc"
|
||||
}, {
|
||||
value: "pdf",
|
||||
label: "pdf"
|
||||
}
|
||||
])
|
||||
|
||||
const tableHeight = ref(400)
|
||||
|
||||
onMounted(() => {
|
||||
let resTypeCache = localStorageCache.get("res-type")
|
||||
let resTypeCache = localStorageCache.get("res-type-arr")
|
||||
if (resTypeCache) {
|
||||
resType.value = resTypeCache
|
||||
resType.value = resTypeCache.split(",")
|
||||
}
|
||||
|
||||
let tableDataCache = localStorageCache.get("res-table-data")
|
||||
@@ -41,37 +72,42 @@ onMounted(() => {
|
||||
tableData.value = tableDataCache
|
||||
}
|
||||
|
||||
ipcRenderer.on('on_get_queue', (res, data) => {
|
||||
// @ts-ignore
|
||||
if (resType.value.includes("all") || resType.value.includes(data.type_str)) {
|
||||
tableData.value.push(data)
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
}
|
||||
})
|
||||
|
||||
ipcRenderer.on('on_down_file_schedule', (res: any, data: any) => {
|
||||
loading.value && loading.value.setText(`${data.schedule}%`)
|
||||
})
|
||||
|
||||
ipcRenderer.invoke('invoke_app_is_init').then((isInit: boolean) => {
|
||||
if (!isInit) {
|
||||
if (!isInit && !isInitApp.value) {
|
||||
isInitApp.value = true
|
||||
ipcRenderer.invoke('invoke_init_app')
|
||||
}
|
||||
})
|
||||
|
||||
const loading = ElLoading.service({
|
||||
loading.value = ElLoading.service({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
|
||||
ipcRenderer.invoke('invoke_start_proxy').then(() => {
|
||||
loading.close()
|
||||
ipcRenderer.on('on_get_queue', (res, data) => {
|
||||
// @ts-ignore
|
||||
if (resType.value.hasOwnProperty(data.type_str) && resType.value[data.type_str]) {
|
||||
tableData.value.push(data)
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
}
|
||||
return
|
||||
})
|
||||
ipcRenderer.invoke('invoke_start_proxy', {upstream_proxy: localStorageCache.get("upstream_proxy")}).then(() => {
|
||||
loading.value.close()
|
||||
}).catch((err) => {
|
||||
// console.log('invoke_start_proxy err', err)
|
||||
ElMessage({
|
||||
message: err,
|
||||
type: 'warning',
|
||||
})
|
||||
loading.close()
|
||||
loading.value.close()
|
||||
})
|
||||
window.addEventListener("resize", handleResize);
|
||||
handleResize()
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -79,12 +115,20 @@ onUnmounted(() => {
|
||||
// console.log(res)
|
||||
})
|
||||
|
||||
ipcRenderer.invoke('invoke_close_proxy').then((res) => {
|
||||
ipcRenderer.removeListener('on_down_file_schedule', (res) => {
|
||||
// console.log(res)
|
||||
})
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
localStorageCache.set("res-type", resType.value, -1)
|
||||
})
|
||||
|
||||
watch(resType, (res, res1) => {
|
||||
localStorageCache.set("res-type-arr", resType.value.join(","), -1)
|
||||
}, {deep: true})
|
||||
|
||||
const handleResize = () => {
|
||||
const height = document.documentElement.clientHeight || window.innerHeight;
|
||||
tableHeight.value = height - 115
|
||||
}
|
||||
|
||||
const handleSelectionChange = (val: resData[]) => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
@@ -94,7 +138,6 @@ const handleBatchDown = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let save_dir = localStorageCache.get("save_dir")
|
||||
|
||||
if (!save_dir) {
|
||||
@@ -105,29 +148,17 @@ const handleBatchDown = async () => {
|
||||
return
|
||||
}
|
||||
|
||||
let loading = ElLoading.service({
|
||||
loading.value = ElLoading.service({
|
||||
lock: true,
|
||||
text: '下载中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
|
||||
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
|
||||
for (const item of multipleSelection.value) {
|
||||
let result = await ipcRenderer.invoke('invoke_file_exists', {
|
||||
save_path: save_dir,
|
||||
url: item.url,
|
||||
})
|
||||
|
||||
if (result.is_file) {
|
||||
item.progress_bar = "100%"
|
||||
item.save_path = result.fileName
|
||||
continue
|
||||
}
|
||||
|
||||
let downRes = await ipcRenderer.invoke('invoke_down_file', {
|
||||
index: 0,
|
||||
data: Object.assign({}, item),
|
||||
save_path: save_dir,
|
||||
high: false
|
||||
quality: quality,
|
||||
})
|
||||
|
||||
if (downRes !== false) {
|
||||
@@ -135,15 +166,13 @@ const handleBatchDown = async () => {
|
||||
item.save_path = downRes.fullFileName
|
||||
}
|
||||
}
|
||||
loading.close()
|
||||
loading.value.close()
|
||||
multipleTableRef.value!.clearSelection()
|
||||
}
|
||||
|
||||
|
||||
const handleDown = async (index: number, row: any, high: boolean) => {
|
||||
|
||||
let save_dir = localStorageCache.get("save_dir")
|
||||
|
||||
const handleDown = async (index: number, row: any) => {
|
||||
const save_dir = localStorageCache.get("save_dir")
|
||||
if (!save_dir) {
|
||||
ElMessage({
|
||||
message: '请设置保存目录',
|
||||
@@ -152,98 +181,112 @@ const handleDown = async (index: number, row: any, high: boolean) => {
|
||||
return
|
||||
}
|
||||
|
||||
let loading = ElLoading.service({
|
||||
loading.value = ElLoading.service({
|
||||
lock: true,
|
||||
text: '下载中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
|
||||
let result = await ipcRenderer.invoke('invoke_file_exists', {
|
||||
save_path: save_dir,
|
||||
url: (high && row.high_url) ? row.high_url : row.url,
|
||||
})
|
||||
|
||||
if (result.is_file) {
|
||||
tableData.value[index].progress_bar = "100%"
|
||||
tableData.value[index].save_path = result.fileName
|
||||
ElMessage({
|
||||
message: "文件已存在(" + result.fileName + ")",
|
||||
type: 'warning',
|
||||
})
|
||||
loading.close()
|
||||
return
|
||||
}
|
||||
|
||||
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
|
||||
ipcRenderer.invoke('invoke_down_file', {
|
||||
index: index,
|
||||
data: Object.assign({}, tableData.value[index]),
|
||||
save_path: save_dir,
|
||||
high: high
|
||||
quality: quality,
|
||||
}).then((res) => {
|
||||
if (res !== false) {
|
||||
tableData.value[index].progress_bar = "100%"
|
||||
tableData.value[index].save_path = res.fullFileName
|
||||
}else{
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "下载失败",
|
||||
type: 'warning',
|
||||
})
|
||||
}
|
||||
loading.close()
|
||||
loading.value.close()
|
||||
}).catch((err) => {
|
||||
// console.log('invoke_down_file err', err)
|
||||
ElMessage({
|
||||
message: "下载失败",
|
||||
type: 'warning',
|
||||
})
|
||||
loading.close()
|
||||
loading.value.close()
|
||||
})
|
||||
}
|
||||
|
||||
const decodeWxFile = (index: number) => {
|
||||
loading.value = ElLoading.service({
|
||||
lock: true,
|
||||
text: "解密中",
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
|
||||
ipcRenderer.invoke('invoke_select_wx_file', {
|
||||
index: index,
|
||||
data: Object.assign({}, tableData.value[index]),
|
||||
}).then((res) => {
|
||||
if (res !== false) {
|
||||
ElMessage({
|
||||
message: "解密成功: " + res.fullFileName,
|
||||
type: 'success',
|
||||
})
|
||||
tableData.value[index].progress_bar = "100%"
|
||||
tableData.value[index].save_path = res.fullFileName
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
} else {
|
||||
ElMessage({
|
||||
message: "解密失败",
|
||||
type: 'warning',
|
||||
})
|
||||
}
|
||||
loading.value.close()
|
||||
}).catch((err) => {
|
||||
ElMessage({
|
||||
message: "解密失败",
|
||||
type: 'warning',
|
||||
})
|
||||
loading.value.close()
|
||||
})
|
||||
}
|
||||
|
||||
const handlePreview = (index: number, row: any) => {
|
||||
// console.log('row.down_url',row)
|
||||
ipcRenderer.invoke('invoke_resources_preview', {url: row.down_url}).catch(() => {
|
||||
ipcRenderer.invoke('invoke_resources_preview', {url: row.url}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
const handleClear = () => {
|
||||
tableData.value = []
|
||||
localStorageCache.del("res-table-data")
|
||||
ipcRenderer.invoke('invoke_file_del', {
|
||||
url_sign: "all"
|
||||
})
|
||||
}
|
||||
|
||||
const handleCopy = (text: string) => {
|
||||
let el = document.createElement('input')
|
||||
el.setAttribute('value', text)
|
||||
document.body.appendChild(el)
|
||||
el.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(el)
|
||||
ElMessage({
|
||||
message: "复制成功",
|
||||
type: 'success',
|
||||
})
|
||||
let el = document.createElement('input')
|
||||
el.setAttribute('value', text)
|
||||
document.body.appendChild(el)
|
||||
el.select()
|
||||
document.execCommand('copy')
|
||||
document.body.removeChild(el)
|
||||
ElMessage({
|
||||
message: "复制成功",
|
||||
type: 'success',
|
||||
})
|
||||
}
|
||||
|
||||
const handleDel = (index: number)=>{
|
||||
const handleDel = (index: number) => {
|
||||
let arr = tableData.value
|
||||
arr.splice(index, 1);
|
||||
tableData.value = arr
|
||||
localStorageCache.set("res-table-data", tableData.value, -1)
|
||||
ipcRenderer.invoke('invoke_file_del', {
|
||||
url_sign: tableData.value[index].url_sign
|
||||
})
|
||||
}
|
||||
|
||||
const openDir = ()=>{
|
||||
let save_dir = localStorageCache.get("save_dir")
|
||||
|
||||
if (!save_dir) {
|
||||
ElMessage({
|
||||
message: '目录不存在',
|
||||
type: 'warning'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ipcRenderer.invoke('invoke_open_dir', {
|
||||
dir: save_dir
|
||||
const openFileDir = (index: number) => {
|
||||
ipcRenderer.invoke('invoke_open_file_dir', {
|
||||
save_path: tableData.value[index].save_path
|
||||
})
|
||||
}
|
||||
|
||||
@@ -261,53 +304,63 @@ const handleInitApp = () => {
|
||||
|
||||
<template lang="pug">
|
||||
el-container.container
|
||||
el-header
|
||||
el-row
|
||||
div
|
||||
el-button(type="primary" @click="handleBatchDown") 批量下载
|
||||
el-button(v-if="isInitApp" @click="handleInitApp")
|
||||
el-icon
|
||||
Promotion
|
||||
p 安装检测(如果看到此按钮说明软件安装未完成则需要手动点击此按钮)
|
||||
el-button(@click="handleClear")
|
||||
el-icon
|
||||
Delete
|
||||
p 清空列表
|
||||
el-button(@click="resType.video=!resType.video" :type="resType.video ? 'primary' : 'info'" ) 视频
|
||||
el-button(@click="resType.audio=!resType.audio" :type="resType.audio ? 'primary' : 'info'" ) 音频
|
||||
el-button(@click="resType.image=!resType.image" :type="resType.image ? 'primary' : 'info'" ) 图片
|
||||
el-button(@click="resType.m3u8=!resType.m3u8" :type="resType.m3u8 ? 'primary' : 'info'" ) m3u8
|
||||
a(style="color: red") 点击左边选项,选择需要拦截的资源类型
|
||||
el-main
|
||||
el-table(ref="multipleTableRef" @selection-change="handleSelectionChange" :data="tableData" max-height="100%" stripe style="max-content")
|
||||
el-table-column(type="selection" width="55")
|
||||
el-table-column(label="预览" show-overflow-tooltip width="350px")
|
||||
template(#default="scope")
|
||||
div.show_res
|
||||
video(v-if="scope.row.type_str === 'video'" :src="scope.row.down_url" controls preload="none" style="width: 100%;height: auto;") 您的浏览器不支持 video 标签。
|
||||
img.img(v-if="scope.row.type_str === 'image'" :src="scope.row.down_url")
|
||||
audio(v-if="scope.row.type_str === 'audio'" controls preload="none")
|
||||
source(:src="scope.row.down_url" :type="scope.row.type")
|
||||
el-table-column(prop="type_str" label="类型" show-overflow-tooltip)
|
||||
el-table-column(prop="platform" label="主机地址")
|
||||
el-table-column(prop="size" label="资源大小")
|
||||
el-table-column(prop="save_path" label="保存目录")
|
||||
el-table-column(prop="progress_bar" label="下载进度")
|
||||
el-table-column(label="操作")
|
||||
template(#default="scope")
|
||||
template(v-if="scope.row.type_str !== 'm3u8'" )
|
||||
el-button(v-if="!scope.row.save_path" link type="primary" @click="handleDown(scope.$index, scope.row, false)") 下载
|
||||
el-button(v-if="!scope.row.save_path && scope.row.high_url !='' " link type="primary" @click="handleDown(scope.$index, scope.row, true)") 高清下载
|
||||
el-header(style="display:flex;align-items: center")
|
||||
el-button(type="primary" @click="handleBatchDown") 批量下载
|
||||
el-button(v-if="isInitApp" @click="handleInitApp")
|
||||
el-icon
|
||||
Promotion
|
||||
p 安装检测(如果看到此按钮说明软件安装未完成则需要手动点击此按钮)
|
||||
el-button(@click="handleClear")
|
||||
el-icon
|
||||
Delete
|
||||
p 清空列表
|
||||
el-select(
|
||||
v-model="resType"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:max-collapse-tags="3"
|
||||
placeholder="资源拦截类型"
|
||||
style="width: auto;min-width:130px"
|
||||
)
|
||||
el-option(v-for="item in typeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value")
|
||||
el-table(ref="multipleTableRef" @selection-change="handleSelectionChange" :data="tableData" :height="tableHeight" max-height="100%" stripe)
|
||||
el-table-column(type="selection")
|
||||
el-table-column(label="预览" show-overflow-tooltip width="150px")
|
||||
template(#default="scope")
|
||||
div.show_res
|
||||
video.video(v-if="scope.row.type_str === 'video'" :src="scope.row.url" controls preload="none")
|
||||
img.img(v-if="scope.row.type_str === 'image'" :src="scope.row.url" crossorigin="anonymous")
|
||||
audio.audio(v-if="scope.row.type_str === 'audio'" controls preload="none")
|
||||
source(:src="scope.row.url" :type="scope.row.type")
|
||||
div(v-if="scope.row.type_str !== 'video' && scope.row.type_str !== 'image' && scope.row.type_str !== 'audio'") {{scope.row.type_str}}类型无法预览
|
||||
div {{scope.row.description}}
|
||||
el-table-column(prop="type_str" label="类型" show-overflow-tooltip)
|
||||
el-table-column(prop="platform" label="主机地址")
|
||||
el-table-column(prop="size" label="资源大小")
|
||||
el-table-column(prop="save_path" label="保存目录" width="135px" :show-overflow-tooltip="true")
|
||||
el-table-column(prop="progress_bar" label="下载进度")
|
||||
el-table-column(label="操作" width="135px" )
|
||||
template(#default="scope")
|
||||
div.actions
|
||||
template(v-if="scope.row.type_str !== 'm3u8' && scope.row.type_str !== 'live'" )
|
||||
el-button(link type="primary" @click="handleDown(scope.$index, scope.row)") {{scope.row.decode_key || scope.row.decryptor_array ? "解密下载(视频号)" : "下载"}}
|
||||
el-button(v-if="scope.row.decode_key || scope.row.decryptor_array" link type="primary" @click="decodeWxFile(scope.$index)") 视频解密(视频号)
|
||||
el-button(link type="primary" @click="handlePreview(scope.$index, scope.row)") 窗口预览
|
||||
el-button(link type="primary" @click="handleCopy(scope.row.down_url)") 复制链接
|
||||
el-button(link type="primary" @click="handleDel(scope.$index)") 删 除
|
||||
el-button(link type="primary" @click="openDir()") 打开目录
|
||||
el-button(link type="primary" @click="handleCopy(scope.row.url)") 复制链接
|
||||
el-button(link type="primary" @click="handleDel(scope.$index)") 删除
|
||||
el-button(v-if="scope.row.save_path" link type="primary" @click="openFileDir(scope.$index)") 打开文件目录
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
.container {
|
||||
padding: 0.5rem;
|
||||
|
||||
.el-table{
|
||||
padding-top: 1rem;
|
||||
}
|
||||
.el-button {
|
||||
margin: 0.1rem;
|
||||
}
|
||||
@@ -335,12 +388,20 @@ el-container.container
|
||||
}
|
||||
}
|
||||
|
||||
.show_res{
|
||||
.img{
|
||||
width: 100px;
|
||||
height: auto;
|
||||
.show_res {
|
||||
.img {
|
||||
max-height: 200px;
|
||||
}
|
||||
.video {
|
||||
width: auto;
|
||||
max-height: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,15 +1,36 @@
|
||||
<script setup lang="ts">
|
||||
import {onMounted, ref} from "vue";
|
||||
import {ipcRenderer} from "electron";
|
||||
import localStorageCache from "../common/localStorage";
|
||||
import {ElMessage} from "element-plus";
|
||||
|
||||
onMounted(() => {
|
||||
saveDir.value = localStorageCache.get("save_dir")
|
||||
saveDir.value = !saveDir.value ? "" : saveDir.value
|
||||
})
|
||||
import {onMounted, ref} from "vue"
|
||||
import {ipcRenderer} from "electron"
|
||||
import localStorageCache from "../common/localStorage"
|
||||
import {ElMessage} from "element-plus"
|
||||
|
||||
const saveDir = ref("")
|
||||
const upstream_proxy = ref("")
|
||||
const upstream_proxy_old = ref("")
|
||||
const quality = ref("-1")
|
||||
const qualityOptions = ref([
|
||||
{
|
||||
value: '-1',
|
||||
label: '默认(推荐)'
|
||||
}, {
|
||||
value: '0',
|
||||
label: '高画质'
|
||||
}, {
|
||||
value: '1',
|
||||
label: '中画质'
|
||||
}, {
|
||||
value: '2',
|
||||
label: '低画质'
|
||||
}
|
||||
])
|
||||
|
||||
onMounted(() => {
|
||||
saveDir.value = localStorageCache.get("save_dir") ? localStorageCache.get("save_dir") : ""
|
||||
quality.value = localStorageCache.get("quality") ? localStorageCache.get("quality") : "-1"
|
||||
upstream_proxy.value = localStorageCache.get("upstream_proxy") ? localStorageCache.get("upstream_proxy") : ""
|
||||
upstream_proxy_old.value = upstream_proxy.value
|
||||
})
|
||||
|
||||
const selectSaveDir = () => {
|
||||
ipcRenderer.invoke('invoke_select_down_dir').then(save_path => {
|
||||
if (save_path !== false) {
|
||||
@@ -20,17 +41,30 @@ const selectSaveDir = () => {
|
||||
|
||||
const onSetting = () => {
|
||||
localStorageCache.set("save_dir", saveDir.value, -1)
|
||||
localStorageCache.set("upstream_proxy", upstream_proxy.value, -1)
|
||||
localStorageCache.set("quality", quality.value, -1)
|
||||
if (upstream_proxy_old.value != upstream_proxy.value){
|
||||
ipcRenderer.invoke('invoke_window_restart')
|
||||
}
|
||||
ElMessage({
|
||||
message: "操作成功",
|
||||
message: "保存成功",
|
||||
type: 'success',
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
<template lang="pug">
|
||||
el-form
|
||||
el-form(style="max-width: 600px")
|
||||
el-form-item(label="保存位置")
|
||||
el-button.select-dir(@click="selectSaveDir") {{saveDir ? saveDir : '选择'}}
|
||||
el-link(@click="selectSaveDir") {{saveDir ? saveDir : '选择'}}
|
||||
el-form-item(label="视频号画质")
|
||||
el-select(v-model="quality" placeholder="请选择")
|
||||
el-option( v-for="item in qualityOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value")
|
||||
el-form-item(label="特殊代理")
|
||||
el-input(v-model="upstream_proxy" placeholder="例如: http://127.0.0.1:7890 修改此项需重启本软件,如不清楚用途请勿设置。" )
|
||||
el-form-item
|
||||
el-button(type="primary" @click="onSetting") 保存
|
||||
</template>
|
||||
</template>
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
<script lang="ts" setup>
|
||||
import {onMounted, ref} from "vue"
|
||||
import {ElMessage} from "element-plus"
|
||||
import {ipcRenderer} from 'electron'
|
||||
import {onUnmounted} from "@vue/runtime-core"
|
||||
import localStorageCache from "../common/localStorage"
|
||||
|
||||
const parseUrls = ref([
|
||||
"https://www.8090g.cn/jiexi/?url=",
|
||||
"https://jx.m3u8.tv/jiexi/?url=",
|
||||
"https://www.playm3u8.cn/jiexi.php?url=",
|
||||
"https://www.8090.la/8090/?url=",
|
||||
"https://jx.xmflv.com/?url=",
|
||||
"https://www.8090g.cn/?url=",
|
||||
"https://dm.xmflv.com:4433/?url=",
|
||||
])
|
||||
|
||||
const useParseUrl = ref("")
|
||||
const playUrl = ref("")
|
||||
const iframeSrc = ref("")
|
||||
const descText = ref(
|
||||
"支持各大视频付费、VIP电影电视剧解析免费观看: 爱奇艺、优酷、腾讯、乐视、土豆、芒果等\r\n若视频播放异常或时长不对,请尝试【更换线路】或【退出软件重新打开】即可解决!\r\n如有线路不行,请把页面拉倒最下方,发邮件给站长!"
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
useParseUrl.value = parseUrls.value[0]
|
||||
let dataCache = localStorageCache.get("res-vip-parse-data")
|
||||
if (dataCache) {
|
||||
useParseUrl.value = dataCache.useParseUrl
|
||||
playUrl.value = dataCache.playUrl
|
||||
// iframeSrc.value = useParseUrl.value + encodeURI(playUrl.value)
|
||||
}
|
||||
})
|
||||
|
||||
const parsePlay = () => {
|
||||
if (!playUrl) {
|
||||
ElMessage({
|
||||
message: "请填写播放地址",
|
||||
type: 'warning',
|
||||
})
|
||||
return
|
||||
}
|
||||
iframeSrc.value = useParseUrl.value + encodeURI(playUrl.value)
|
||||
}
|
||||
|
||||
const parseFullPlay = () => {
|
||||
if (!playUrl) {
|
||||
ElMessage({
|
||||
message: "请填写播放地址",
|
||||
type: 'warning',
|
||||
})
|
||||
return
|
||||
}
|
||||
ipcRenderer.invoke('invoke_resources_preview', {url: useParseUrl.value + encodeURI(playUrl.value)}).catch(() => {
|
||||
})
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
localStorageCache.set("res-vip-parse-data", {useParseUrl: useParseUrl.value, playUrl: playUrl.value}, -1)
|
||||
})
|
||||
|
||||
</script>
|
||||
<template lang="pug">
|
||||
el-main.play-box
|
||||
iframe.iframe(:src="iframeSrc")
|
||||
el-form
|
||||
el-form-item(label="线路选择:")
|
||||
el-select(v-model="useParseUrl")
|
||||
el-option(v-for="(v, k) in parseUrls" :value="v" :label="'线路'+(k+1)")
|
||||
el-form-item(label="播放地址:")
|
||||
el-input(v-model="playUrl" type="textarea" placeholder="爱奇艺、优酷、腾讯、芒果、乐视、土豆")
|
||||
el-form-item
|
||||
el-button(type="primary" @click="parsePlay()") 立即播放
|
||||
el-button(type="primary" @click="parseFullPlay()") 全屏播放
|
||||
el-row.desc {{descText}}
|
||||
</template>
|
||||
<style scoped lang="less">
|
||||
.play-box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.iframe {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border: 0;
|
||||
background-color: #211f1f;
|
||||
width: 100%;
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
.desc {
|
||||
color: red;
|
||||
font-size: 20px;
|
||||
white-space: pre-wrap;
|
||||
text-align: left;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user