mirror of
https://github.com/putyy/res-downloader.git
synced 2026-01-12 06:04:55 +08:00
优化代理启动、增加table筛选等
This commit is contained in:
2
components.d.ts
vendored
2
components.d.ts
vendored
@@ -8,6 +8,7 @@ export {}
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
|
||||
ElContainer: typeof import('element-plus/es')['ElContainer']
|
||||
ElFooter: typeof import('element-plus/es')['ElFooter']
|
||||
ElForm: typeof import('element-plus/es')['ElForm']
|
||||
@@ -20,6 +21,7 @@ declare module 'vue' {
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
Footer: typeof import('./src/components/layout/Footer.vue')['default']
|
||||
|
||||
@@ -9,51 +9,62 @@ export function checkCertInstalled() {
|
||||
return fs.existsSync(CONFIG.INSTALL_CERT_FLAG)
|
||||
}
|
||||
|
||||
export async function installCert(checkInstalled = true) {
|
||||
if (checkInstalled && checkCertInstalled()) {
|
||||
return;
|
||||
}
|
||||
mkdirp.sync(path.dirname(CONFIG.INSTALL_CERT_FLAG))
|
||||
export function installCert(checkInstalled = true) {
|
||||
try {
|
||||
if (checkInstalled && checkCertInstalled()) {
|
||||
return;
|
||||
}
|
||||
mkdirp.sync(path.dirname(CONFIG.INSTALL_CERT_FLAG))
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
return new Promise((resolve, reject) => {
|
||||
clipboard.writeText(
|
||||
`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",
|
||||
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 {
|
||||
return new Promise((resolve: any, reject) => {
|
||||
const result = spawn.sync(CONFIG.WIN_CERT_INSTALL_HELPER, [
|
||||
'-c',
|
||||
'-add',
|
||||
CONFIG.CERT_PUBLIC_PATH,
|
||||
'-s',
|
||||
'root',
|
||||
]);
|
||||
if (result.stdout.toString().indexOf('Succeeded') > -1) {
|
||||
fs.writeFileSync(CONFIG.INSTALL_CERT_FLAG, '')
|
||||
resolve()
|
||||
} else {
|
||||
reject()
|
||||
}
|
||||
})
|
||||
if (process.platform === 'darwin') {
|
||||
handleMacCertInstallation()
|
||||
} else if (process.platform === 'win32') {
|
||||
handleWindowsCertInstallation()
|
||||
} else {
|
||||
handleOtherCertInstallation()
|
||||
}
|
||||
} catch (e) {
|
||||
handleOtherCertInstallation()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MacOS 证书安装处理
|
||||
function handleMacCertInstallation() {
|
||||
clipboard.writeText(
|
||||
`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',
|
||||
message: '命令已复制到剪贴板,粘贴到终端并运行以安装并信任证书',
|
||||
});
|
||||
}
|
||||
|
||||
// Linux 证书安装处理
|
||||
function handleOtherCertInstallation() {
|
||||
clipboard.writeText(CONFIG.CERT_PUBLIC_PATH);
|
||||
|
||||
dialog.showMessageBoxSync({
|
||||
type: "info",
|
||||
message: `请手动安装证书,证书文件路径:${CONFIG.CERT_PUBLIC_PATH} 已复制到剪贴板`,
|
||||
});
|
||||
}
|
||||
|
||||
// Windows 证书安装处理
|
||||
function handleWindowsCertInstallation() {
|
||||
const result = spawn.sync(CONFIG.WIN_CERT_INSTALL_HELPER, [
|
||||
'-c',
|
||||
'-add',
|
||||
CONFIG.CERT_PUBLIC_PATH,
|
||||
'-s',
|
||||
'root',
|
||||
]);
|
||||
|
||||
if (result.stdout.toString().includes('Succeeded')) {
|
||||
fs.writeFileSync(CONFIG.INSTALL_CERT_FLAG, '');
|
||||
} else {
|
||||
handleOtherCertInstallation();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import {closeProxy} from "./setProxy"
|
||||
import log from "electron-log"
|
||||
import path from 'path'
|
||||
import {spawn} from 'child_process'
|
||||
import {startServer} from "./proxyServer";
|
||||
import fs from "fs";
|
||||
|
||||
// The built directory structure
|
||||
//
|
||||
@@ -56,6 +58,16 @@ const preload = join(__dirname, '../preload/index.js')
|
||||
const url = process.env.VITE_DEV_SERVER_URL
|
||||
const indexHtml = join(process.env.DIST, 'index.html')
|
||||
|
||||
global.videoList = {}
|
||||
global.isStartProxy = false
|
||||
global.isSettingProxy = false
|
||||
global.resdConfig = {
|
||||
save_dir: "",
|
||||
quality: "-1",
|
||||
proxy: "",
|
||||
port: 8899,
|
||||
}
|
||||
|
||||
// app.whenReady().then(createWindow)
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
@@ -100,8 +112,10 @@ function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
title: 'Main window',
|
||||
icon: join(process.env.VITE_PUBLIC, 'favicon.ico'),
|
||||
width: 800,
|
||||
height: 600,
|
||||
width: 1024,
|
||||
minWidth: 960,
|
||||
height: 768,
|
||||
minHeight: 640,
|
||||
webPreferences: {
|
||||
preload,
|
||||
// Warning: Enable nodeIntegration and disable contextIsolation is not secure in production
|
||||
@@ -206,10 +220,32 @@ function createAria2Process() {
|
||||
}
|
||||
}
|
||||
|
||||
function initConfig(){
|
||||
const configPath = path.join(app.getPath('userData'), 'resd_config.json')
|
||||
if (!fs.existsSync(configPath)) {
|
||||
return
|
||||
}
|
||||
fs.readFile(configPath, (err, data) => {
|
||||
if (!err) {
|
||||
try {
|
||||
const jsonData = JSON.parse(data)
|
||||
console.log("jsonData:", jsonData)
|
||||
global.resdConfig = Object.assign({}, global.resdConfig, jsonData)
|
||||
if (!global.resdConfig.proxy) {
|
||||
global.resdConfig.proxy = "8899"
|
||||
}
|
||||
} catch (parseErr) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
app.whenReady().then(() => {
|
||||
initIPC()
|
||||
createWindow()
|
||||
createPreviewWindow(mainWindow)
|
||||
createAria2Process()
|
||||
setWin(mainWindow, previewWin)
|
||||
initConfig()
|
||||
initIPC()
|
||||
startServer(mainWindow)
|
||||
createAria2Process()
|
||||
})
|
||||
@@ -7,10 +7,12 @@ import {hexMD5} from '../../src/common/md5'
|
||||
import {Aria2RPC} from './aria2Rpc'
|
||||
import fs from "fs"
|
||||
import urlTool from "url";
|
||||
import {setProxy} from "./setProxy";
|
||||
import path from 'path'
|
||||
|
||||
let win: BrowserWindow
|
||||
let previewWin: BrowserWindow
|
||||
let isStartProxy = false
|
||||
|
||||
const aria2RpcClient = new Aria2RPC()
|
||||
|
||||
export default function initIPC() {
|
||||
@@ -21,23 +23,50 @@ export default function initIPC() {
|
||||
|
||||
ipcMain.handle('invoke_init_app', (event, arg) => {
|
||||
// 开始 初始化应用 安装证书相关
|
||||
installCert(false).then(r => {
|
||||
})
|
||||
installCert(false)
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_start_proxy', (event, arg) => {
|
||||
ipcMain.handle('invoke_set_config', (event, data) => {
|
||||
const filePath = path.join(app.getPath('userData'), 'resd_config.json');
|
||||
fs.writeFile(filePath, JSON.stringify(data), ()=>{})
|
||||
global.resdConfig = Object.assign({}, global.resdConfig, data)
|
||||
global.resdConfig.port = parseInt(global.resdConfig.port)
|
||||
return true
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_set_proxy', async (event, arg) => {
|
||||
// 启动代理服务
|
||||
if (isStartProxy) {
|
||||
return
|
||||
if (!global.isStartProxy) {
|
||||
dialog.showMessageBoxSync({
|
||||
type: "error",
|
||||
message: "代理未启动",
|
||||
});
|
||||
return false
|
||||
}
|
||||
isStartProxy = true
|
||||
return startServer({
|
||||
win: win,
|
||||
upstreamProxy: arg.upstream_proxy ? arg.upstream_proxy : "",
|
||||
setProxyErrorCallback: err => {
|
||||
console.log('setProxyErrorCallback', err)
|
||||
},
|
||||
})
|
||||
try {
|
||||
await setProxy('127.0.0.1', global.resdConfig.proxy)
|
||||
return true
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
dialog.showMessageBoxSync({
|
||||
type: "error",
|
||||
message: err.toString(),
|
||||
});
|
||||
return false
|
||||
}
|
||||
// let upstream_proxy = ""
|
||||
// if (arg.upstream_proxy && !arg.upstream_proxy.includes(':8899')) {
|
||||
// upstream_proxy = arg.upstream_proxy
|
||||
// }
|
||||
//
|
||||
// global.isStartProxy = true
|
||||
// return startServer({
|
||||
// win: win,
|
||||
// upstreamProxy: upstream_proxy,
|
||||
// setProxyErrorCallback: err => {
|
||||
// console.log('setProxyErrorCallback', err)
|
||||
// },
|
||||
// })
|
||||
})
|
||||
|
||||
ipcMain.handle('invoke_select_down_dir', async (event, arg) => {
|
||||
@@ -72,7 +101,7 @@ export default function initIPC() {
|
||||
resolve(false);
|
||||
});
|
||||
}
|
||||
if(quality === "0" && data.decode_key){
|
||||
if (quality === "0" && data.decode_key) {
|
||||
const urlInfo = urlTool.parse(down_url, true);
|
||||
console.log('urlInfo', urlInfo)
|
||||
if (urlInfo.query["token"] && urlInfo.query["encfilekey"]) {
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
import fs from 'fs'
|
||||
import log from 'electron-log'
|
||||
import CONFIG from './const'
|
||||
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'
|
||||
import {dialog} from "electron";
|
||||
|
||||
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
|
||||
@@ -34,144 +30,154 @@ const resObject = {
|
||||
description: ""
|
||||
}
|
||||
|
||||
const vv = hexMD5(pkg.version) + (CONFIG.IS_DEV ? Math.random() :"")
|
||||
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) => {
|
||||
try {
|
||||
const proxy = hoXy.createServer({
|
||||
upstreamProxy: upstreamProxy,
|
||||
certAuthority: {
|
||||
key: fs.readFileSync(CONFIG.CERT_PRIVATE_PATH),
|
||||
cert: fs.readFileSync(CONFIG.CERT_PUBLIC_PATH),
|
||||
},
|
||||
export function startServer(win) {
|
||||
try {
|
||||
let upstreamProxy = ""
|
||||
if (global.resdConfig.proxy && !global.resdConfig.proxy.includes(':' + global.resdConfig.port)) {
|
||||
upstreamProxy = global.resdConfig?.proxy
|
||||
}
|
||||
const proxy = hoXy.createServer({
|
||||
upstreamProxy: upstreamProxy,
|
||||
certAuthority: {
|
||||
key: fs.readFileSync(CONFIG.CERT_PRIVATE_PATH),
|
||||
cert: fs.readFileSync(CONFIG.CERT_PUBLIC_PATH),
|
||||
},
|
||||
})
|
||||
.listen(global.resdConfig.port, () => {
|
||||
global.isStartProxy = true
|
||||
// try {
|
||||
// await setProxy('127.0.0.1', port)
|
||||
// resolve()
|
||||
// } catch (err) {
|
||||
// console.error(err);
|
||||
// setProxyErrorCallback(err)
|
||||
// reject("请手动设置系统代理" + err.toString())
|
||||
// }
|
||||
})
|
||||
.listen(port, async () => {
|
||||
try {
|
||||
await setProxy('127.0.0.1', port)
|
||||
resolve()
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setProxyErrorCallback(err)
|
||||
reject("请手动设置系统代理" + err.toString())
|
||||
}
|
||||
})
|
||||
.on('error', err => {
|
||||
setProxyErrorCallback(err)
|
||||
reject('proxy service err: ' + err.toString())
|
||||
})
|
||||
.on('error', err => {
|
||||
console.error(err);
|
||||
dialog.showMessageBoxSync({
|
||||
type: 'error',
|
||||
message: err.toString(),
|
||||
});
|
||||
// setProxyErrorCallback(err)
|
||||
// reject('proxy service err: ' + err.toString())
|
||||
})
|
||||
intercept(proxy, win)
|
||||
} catch (e) {
|
||||
log.log("--------------proxy catch err--------------", e)
|
||||
}
|
||||
}
|
||||
|
||||
function intercept(proxy, win) {
|
||||
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: '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
|
||||
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,
|
||||
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,
|
||||
size: toSize(contentLength ? contentLength : 0),
|
||||
type: contentType,
|
||||
type_str: resType,
|
||||
}))
|
||||
} 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)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
log.log("--------------proxy response err--------------", e)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -38,7 +38,7 @@ export async function setProxy(host, port) {
|
||||
} else if (process.platform === 'linux') {
|
||||
dialog.showMessageBoxSync({
|
||||
type: "info",
|
||||
message: `请手动设置系统代理`,
|
||||
message: `请手动设置系统代理 默认为: 127.0.0.1:8899`,
|
||||
});
|
||||
return new Promise((resolve, reject) => {})
|
||||
} else {
|
||||
|
||||
@@ -99,7 +99,7 @@ function toSize(size: number) {
|
||||
}
|
||||
|
||||
function typeSuffix(type: string) {
|
||||
switch (type) {
|
||||
switch (type ? type.toLowerCase() : type) {
|
||||
case "video/mp4":
|
||||
case "video/webm":
|
||||
case "video/ogg":
|
||||
@@ -111,7 +111,7 @@ function typeSuffix(type: string) {
|
||||
case "video/x-matroska":
|
||||
return ["video", ".mp4"];
|
||||
case "audio/video":
|
||||
case "video/x-flv":
|
||||
case "video/x-flv":
|
||||
return ["live", ".mp4"];
|
||||
case "image/png":
|
||||
case "image/webp":
|
||||
@@ -143,7 +143,7 @@ function typeSuffix(type: string) {
|
||||
case "audio/mp4;charset=UTF-8":
|
||||
return ["audio", ".mp3"];
|
||||
case "application/vnd.apple.mpegurl":
|
||||
case "application/x-mpegURL":
|
||||
case "application/x-mpegurl":
|
||||
return ["m3u8", ".m3u8"];
|
||||
case "application/pdf":
|
||||
return ["pdf", ".pdf"];
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<router-view></router-view>
|
||||
<el-config-provider :locale="zhCn">
|
||||
<router-view></router-view>
|
||||
</el-config-provider>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
import request from './request'
|
||||
|
||||
export function getPackageJson() {
|
||||
return request.get("https://github.com/putyy/res-downloader/raw/main/package.json")
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
import axios from 'axios'
|
||||
import {ElMessage} from 'element-plus'
|
||||
import {hexMD5} from "./md5"
|
||||
import localStorageCache from "./localStorage"
|
||||
import _ from "lodash"
|
||||
|
||||
class RequestService {
|
||||
private axios: any;
|
||||
private requestList: any;
|
||||
constructor() {
|
||||
let that = this
|
||||
that.requestList = []
|
||||
that.axios = axios.create({
|
||||
timeout: 60000, // 请求超时时间毫秒
|
||||
})
|
||||
|
||||
// 请求拦截
|
||||
that.axios.interceptors.request.use(
|
||||
function (config: any) {
|
||||
if (config.url.slice(0, 8) !== "https://") {
|
||||
config.url = import.meta.env.VITE_APP_API + "/" + config.url
|
||||
}
|
||||
return config
|
||||
},
|
||||
function (error: any) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截
|
||||
that.axios.interceptors.response.use(
|
||||
function (response: any) {
|
||||
return response
|
||||
},
|
||||
function (error: any) {
|
||||
// console.log(error)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
get(url: string, data?: any) {
|
||||
return this.axios.get(url, {params: data}).catch((err:any)=>{
|
||||
console.log('get-err', err)
|
||||
})
|
||||
}
|
||||
|
||||
post(url: string, data: any, isHandle?: any) {
|
||||
isHandle = isHandle || true
|
||||
if (isHandle){
|
||||
data = Object.keys(data).map(item => {
|
||||
let value = data[item];
|
||||
if (_.isArray(value) || _.isObject(value)) {
|
||||
value = JSON.stringify(value)
|
||||
}
|
||||
return encodeURIComponent(item) + '=' + encodeURIComponent(value)
|
||||
}).join('&');
|
||||
}
|
||||
return this.axios.post(url, data).catch((err:any)=>{
|
||||
console.log('post-err', err)
|
||||
})
|
||||
}
|
||||
|
||||
axiosObj() {
|
||||
return this.axios
|
||||
}
|
||||
}
|
||||
|
||||
const request = new RequestService()
|
||||
export default request
|
||||
@@ -1,14 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import {inject, onMounted, ref, watch} from 'vue'
|
||||
import localStorageCache from "../../common/localStorage"
|
||||
|
||||
const appName = "爱享素材"
|
||||
const sidebarCollapse = ref(inject('sidebarCollapse'))
|
||||
const defaultActive = ref("/index")
|
||||
|
||||
onMounted(() => {
|
||||
let lastRoute = localStorageCache.get('last-route')
|
||||
defaultActive.value = lastRoute ? lastRoute : "/index"
|
||||
defaultActive.value = "/index"
|
||||
})
|
||||
</script>
|
||||
<template lang="pug">
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import {createMemoryHistory, createRouter} from 'vue-router'
|
||||
// @ts-ignore
|
||||
import localStorageCache from "./common/localStorage"
|
||||
|
||||
const routes = [
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {ref, onMounted, onUnmounted, watch} from "vue"
|
||||
import {ref, onMounted, onUnmounted, watch, computed} from "vue"
|
||||
import {ipcRenderer} from 'electron'
|
||||
import {ElMessage, ElLoading, ElTable} from "element-plus"
|
||||
import localStorageCache from "../common/localStorage"
|
||||
import {Delete, Promotion} from "@element-plus/icons-vue"
|
||||
import {Delete, Filter, Promotion} from "@element-plus/icons-vue"
|
||||
|
||||
interface resData {
|
||||
url: string,
|
||||
@@ -18,10 +18,41 @@ interface resData {
|
||||
description: string,
|
||||
}
|
||||
|
||||
const filtersAction = ref({
|
||||
descInput: "",
|
||||
descVisible: false,
|
||||
descValue: "",
|
||||
typeInput: [],
|
||||
typeVisible: false,
|
||||
typeValue: [],
|
||||
})
|
||||
|
||||
const tableData = ref<resData[]>([])
|
||||
|
||||
const filteredData = computed(() => {
|
||||
if (filtersAction.value.descValue && filtersAction.value.typeValue.length === 0) {
|
||||
return tableData.value.filter(item => {
|
||||
return item.description.includes(filtersAction.value.descValue)
|
||||
});
|
||||
}
|
||||
|
||||
if (!filtersAction.value.descValue && filtersAction.value.typeValue.length > 0) {
|
||||
return tableData.value.filter(item => {
|
||||
return filtersAction.value.typeValue.includes(item.type_str)
|
||||
});
|
||||
}
|
||||
|
||||
if (filtersAction.value.descValue && filtersAction.value.typeValue.length > 0) {
|
||||
return tableData.value.filter(item => {
|
||||
return item.description.includes(filtersAction.value.descValue) && filtersAction.value.typeValue.includes(item.type_str)
|
||||
});
|
||||
}
|
||||
|
||||
return tableData.value
|
||||
});
|
||||
|
||||
const isInitApp = ref(false)
|
||||
const isSetProxy = ref(false)
|
||||
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
const multipleSelection = ref<resData[]>([])
|
||||
@@ -59,6 +90,8 @@ const typeOptions = ref([
|
||||
}
|
||||
])
|
||||
|
||||
const typeFilters = ref(Array.from(typeOptions.value).slice(1))
|
||||
|
||||
const tableHeight = ref(400)
|
||||
|
||||
onMounted(() => {
|
||||
@@ -91,21 +124,21 @@ onMounted(() => {
|
||||
}
|
||||
})
|
||||
|
||||
loading.value = ElLoading.service({
|
||||
lock: true,
|
||||
text: 'Loading',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
// loading.value = ElLoading.service({
|
||||
// lock: true,
|
||||
// text: 'Loading',
|
||||
// background: 'rgba(0, 0, 0, 0.7)',
|
||||
// })
|
||||
|
||||
ipcRenderer.invoke('invoke_start_proxy', {upstream_proxy: localStorageCache.get("upstream_proxy")}).then(() => {
|
||||
loading.value.close()
|
||||
}).catch((err) => {
|
||||
ElMessage({
|
||||
message: err,
|
||||
type: 'warning',
|
||||
})
|
||||
loading.value.close()
|
||||
})
|
||||
// ipcRenderer.invoke('invoke_start_proxy', {upstream_proxy: localStorageCache.get("upstream_proxy")}).then(() => {
|
||||
// loading.value.close()
|
||||
// }).catch((err) => {
|
||||
// ElMessage({
|
||||
// message: err,
|
||||
// type: 'warning',
|
||||
// })
|
||||
// loading.value.close()
|
||||
// })
|
||||
window.addEventListener("resize", handleResize);
|
||||
handleResize()
|
||||
})
|
||||
@@ -137,8 +170,9 @@ const handleBatchDown = async () => {
|
||||
if (multipleSelection.value.length <= 0) {
|
||||
return
|
||||
}
|
||||
const config = resdConfig()
|
||||
|
||||
let save_dir = localStorageCache.get("save_dir")
|
||||
const save_dir = config?.save_dir
|
||||
|
||||
if (!save_dir) {
|
||||
ElMessage({
|
||||
@@ -153,7 +187,7 @@ const handleBatchDown = async () => {
|
||||
text: '下载中',
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
|
||||
const quality = config?.quality ? config?.quality : -1
|
||||
for (const item of multipleSelection.value) {
|
||||
let downRes = await ipcRenderer.invoke('invoke_down_file', {
|
||||
data: Object.assign({}, item),
|
||||
@@ -172,7 +206,8 @@ const handleBatchDown = async () => {
|
||||
|
||||
|
||||
const handleDown = async (index: number, row: any) => {
|
||||
const save_dir = localStorageCache.get("save_dir")
|
||||
const config = resdConfig()
|
||||
const save_dir = config?.save_dir
|
||||
if (!save_dir) {
|
||||
ElMessage({
|
||||
message: '请设置保存目录',
|
||||
@@ -187,7 +222,7 @@ const handleDown = async (index: number, row: any) => {
|
||||
background: 'rgba(0, 0, 0, 0.7)',
|
||||
})
|
||||
|
||||
const quality = localStorageCache.get("quality") ? localStorageCache.get("quality") : -1
|
||||
const quality = config?.quality ? config?.quality : -1
|
||||
ipcRenderer.invoke('invoke_down_file', {
|
||||
data: Object.assign({}, tableData.value[index]),
|
||||
save_path: save_dir,
|
||||
@@ -300,11 +335,46 @@ const handleInitApp = () => {
|
||||
})
|
||||
}
|
||||
|
||||
const setProxy = ()=>{
|
||||
isSetProxy.value = !isSetProxy.value
|
||||
ipcRenderer.invoke('invoke_set_proxy', {proxy: isSetProxy.value}).then((res) => {
|
||||
if (res) {
|
||||
ElMessage({
|
||||
type: "warning",
|
||||
message: "设置系统代理失败",
|
||||
})
|
||||
}
|
||||
}).catch((err) => {
|
||||
ElMessage({
|
||||
type: "warning",
|
||||
message: err,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const handleFilter = (type: string)=>{
|
||||
if (type === "desc") {
|
||||
filtersAction.value.descValue = filtersAction.value.descInput
|
||||
filtersAction.value.descVisible = false
|
||||
return
|
||||
}
|
||||
filtersAction.value.typeValue = filtersAction.value.typeInput
|
||||
filtersAction.value.typeVisible = false
|
||||
}
|
||||
|
||||
const resdConfig = ()=>{
|
||||
const cache = localStorageCache.get("resd_config")
|
||||
if (cache) {
|
||||
return JSON.parse(cache)
|
||||
}
|
||||
return null
|
||||
}
|
||||
</script>
|
||||
|
||||
<template lang="pug">
|
||||
el-container.container
|
||||
el-header(style="display:flex;align-items: center")
|
||||
el-button(:type="isSetProxy ? 'primary' : 'info'" @click="setProxy") {{isSetProxy ? '关闭代理' : '启动代理'}}
|
||||
el-button(type="primary" @click="handleBatchDown") 批量下载
|
||||
el-button(v-if="isInitApp" @click="handleInitApp")
|
||||
el-icon
|
||||
@@ -327,9 +397,21 @@ el-container.container
|
||||
: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(ref="multipleTableRef" @selection-change="handleSelectionChange" :data="filteredData" :height="tableHeight" max-height="100%" stripe)
|
||||
el-table-column(type="selection")
|
||||
el-table-column(label="预览" show-overflow-tooltip width="150px")
|
||||
template(#header)
|
||||
div(style="display:flex;align-items: center")
|
||||
span(:style="filtersAction.descValue ? 'color: #409eff' : ''") 信息
|
||||
el-popover(:visible="filtersAction.descVisible")
|
||||
div
|
||||
el-input(v-model="filtersAction.descInput" placeholder="请输入")
|
||||
div(style="margin-top:10px;display:flex;justify-content: center;")
|
||||
el-button(size="small" @click="filtersAction.descVisible = false") 关闭
|
||||
el-button(size="small" type="primary" @click="handleFilter('desc')") 筛选
|
||||
template(#reference)
|
||||
el-icon(@click="filtersAction.descVisible = true")
|
||||
Filter
|
||||
template(#default="scope")
|
||||
div.show_res
|
||||
video.video(v-if="scope.row.type_str === 'video'" :src="scope.row.url" controls preload="none")
|
||||
@@ -339,6 +421,30 @@ el-container.container
|
||||
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)
|
||||
template(#header)
|
||||
div(style="display:flex;align-items: center")
|
||||
span(:style="filtersAction.typeValue.length > 0 ? 'color: #409eff' : ''") 类型
|
||||
el-popover(:visible="filtersAction.typeVisible")
|
||||
div
|
||||
el-select(
|
||||
v-model="filtersAction.typeInput"
|
||||
multiple
|
||||
collapse-tags
|
||||
collapse-tags-tooltip
|
||||
:max-collapse-tags="3"
|
||||
placeholder="资源拦截类型"
|
||||
style="width: auto;min-width:130px"
|
||||
)
|
||||
el-option(v-for="item in typeFilters"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value")
|
||||
div(style="margin-top:10px;display:flex;justify-content: center;")
|
||||
el-button(size="small" @click="filtersAction.typeVisible = false") 关闭
|
||||
el-button(size="small" type="primary" @click="handleFilter('type')") 筛选
|
||||
template(#reference)
|
||||
el-icon(@click="filtersAction.typeVisible = true")
|
||||
Filter
|
||||
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")
|
||||
|
||||
@@ -4,6 +4,15 @@ import {ipcRenderer} from "electron"
|
||||
import localStorageCache from "../common/localStorage"
|
||||
import {ElMessage} from "element-plus"
|
||||
|
||||
const formData = ref({
|
||||
save_dir: "",
|
||||
quality: "-1",
|
||||
proxy: "",
|
||||
port: "8899",
|
||||
})
|
||||
const proxy_old = ref("")
|
||||
const port_old = ref("")
|
||||
|
||||
const saveDir = ref("")
|
||||
const upstream_proxy = ref("")
|
||||
const upstream_proxy_old = ref("")
|
||||
@@ -25,27 +34,29 @@ const qualityOptions = ref([
|
||||
])
|
||||
|
||||
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 cache = localStorageCache.get("resd_config")
|
||||
if (cache) {
|
||||
formData.value = JSON.parse(cache)
|
||||
}
|
||||
proxy_old.value = formData.value.proxy
|
||||
port_old.value = formData.value.port
|
||||
})
|
||||
|
||||
const selectSaveDir = () => {
|
||||
ipcRenderer.invoke('invoke_select_down_dir').then(save_path => {
|
||||
if (save_path !== false) {
|
||||
saveDir.value = save_path
|
||||
ipcRenderer.invoke('invoke_select_down_dir').then(save_dir => {
|
||||
if (save_dir !== false) {
|
||||
formData.value.save_dir = save_dir
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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){
|
||||
localStorageCache.set("resd_config", JSON.stringify(formData.value))
|
||||
ipcRenderer.invoke('invoke_set_config', Object.assign({}, formData.value))
|
||||
if (proxy_old.value != formData.value.proxy || port_old.value != formData.value.port){
|
||||
ipcRenderer.invoke('invoke_window_restart')
|
||||
}
|
||||
|
||||
ElMessage({
|
||||
message: "保存成功",
|
||||
type: 'success',
|
||||
@@ -55,16 +66,18 @@ const onSetting = () => {
|
||||
</script>
|
||||
<template lang="pug">
|
||||
el-form(style="max-width: 600px")
|
||||
el-form-item(label="代理端口")
|
||||
el-input(v-model="formData.proxy" placeholder="默认: 8899" )
|
||||
el-form-item(label="保存位置")
|
||||
el-link(@click="selectSaveDir") {{saveDir ? saveDir : '选择'}}
|
||||
el-form-item(label="视频号画质")
|
||||
el-select(v-model="quality" placeholder="请选择")
|
||||
el-select(v-model="formData.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-input(v-model="formData.proxy" placeholder="例如: http://127.0.0.1:7890 修改此项需重启本软件,如不清楚用途请勿设置。" )
|
||||
el-form-item
|
||||
el-button(type="primary" @click="onSetting") 保存
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user