mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-14 06:30:49 +08:00
✨ feat: 添加代理功能和 realIP配置功能
This commit is contained in:
@@ -1,11 +1,43 @@
|
|||||||
import { BrowserWindow, shell, ipcMain, app } from 'electron';
|
import { BrowserWindow, shell, ipcMain, app, session } from 'electron';
|
||||||
import { is } from '@electron-toolkit/utils';
|
import { is } from '@electron-toolkit/utils';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import Store from 'electron-store';
|
||||||
|
|
||||||
|
const store = new Store();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化代理设置
|
||||||
|
*/
|
||||||
|
function initializeProxy() {
|
||||||
|
const defaultConfig = {
|
||||||
|
enable: false,
|
||||||
|
protocol: 'http',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7890
|
||||||
|
};
|
||||||
|
|
||||||
|
const proxyConfig = store.get('set.proxyConfig', defaultConfig) as {
|
||||||
|
enable: boolean;
|
||||||
|
protocol: string;
|
||||||
|
host: string;
|
||||||
|
port: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (proxyConfig?.enable) {
|
||||||
|
const proxyRules = `${proxyConfig.protocol}://${proxyConfig.host}:${proxyConfig.port}`;
|
||||||
|
session.defaultSession.setProxy({ proxyRules });
|
||||||
|
} else {
|
||||||
|
session.defaultSession.setProxy({ proxyRules: '' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化窗口管理相关的IPC监听
|
* 初始化窗口管理相关的IPC监听
|
||||||
*/
|
*/
|
||||||
export function initializeWindowManager() {
|
export function initializeWindowManager() {
|
||||||
|
// 初始化代理设置
|
||||||
|
initializeProxy();
|
||||||
|
|
||||||
ipcMain.on('minimize-window', (event) => {
|
ipcMain.on('minimize-window', (event) => {
|
||||||
const win = BrowserWindow.fromWebContents(event.sender);
|
const win = BrowserWindow.fromWebContents(event.sender);
|
||||||
if (win) {
|
if (win) {
|
||||||
@@ -38,6 +70,11 @@ export function initializeWindowManager() {
|
|||||||
win.hide();
|
win.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听代理设置变化
|
||||||
|
store.onDidChange('set.proxyConfig', () => {
|
||||||
|
initializeProxy();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
{
|
{
|
||||||
"isProxy": false,
|
"isProxy": false,
|
||||||
|
"proxyConfig": {
|
||||||
|
"enable": false,
|
||||||
|
"protocol": "http",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": 7890
|
||||||
|
},
|
||||||
|
"enableRealIP":false,
|
||||||
|
"realIP":"",
|
||||||
"noAnimate": false,
|
"noAnimate": false,
|
||||||
"animationSpeed": 1,
|
"animationSpeed": 1,
|
||||||
"author": "Alger",
|
"author": "Alger",
|
||||||
|
|||||||
2
src/renderer/components.d.ts
vendored
2
src/renderer/components.d.ts
vendored
@@ -17,6 +17,8 @@ declare module 'vue' {
|
|||||||
NDropdown: typeof import('naive-ui')['NDropdown']
|
NDropdown: typeof import('naive-ui')['NDropdown']
|
||||||
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
NEllipsis: typeof import('naive-ui')['NEllipsis']
|
||||||
NEmpty: typeof import('naive-ui')['NEmpty']
|
NEmpty: typeof import('naive-ui')['NEmpty']
|
||||||
|
NForm: typeof import('naive-ui')['NForm']
|
||||||
|
NFormItem: typeof import('naive-ui')['NFormItem']
|
||||||
NImage: typeof import('naive-ui')['NImage']
|
NImage: typeof import('naive-ui')['NImage']
|
||||||
NInput: typeof import('naive-ui')['NInput']
|
NInput: typeof import('naive-ui')['NInput']
|
||||||
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
NInputNumber: typeof import('naive-ui')['NInputNumber']
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
import axios, { InternalAxiosRequestConfig } from 'axios';
|
import axios, { InternalAxiosRequestConfig } from 'axios';
|
||||||
|
import { isElectron } from '.';
|
||||||
|
|
||||||
let setData: any = null;
|
let setData: any = null;
|
||||||
|
|
||||||
if (window.electron) {
|
const getSetData = ()=>{
|
||||||
setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
if (window.electron) {
|
||||||
|
setData = window.electron.ipcRenderer.sendSync('get-store-value', 'set');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
getSetData()
|
||||||
// 扩展请求配置接口
|
// 扩展请求配置接口
|
||||||
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
|
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
|
||||||
retryCount?: number;
|
retryCount?: number;
|
||||||
@@ -26,15 +29,18 @@ const RETRY_DELAY = 500;
|
|||||||
// 请求拦截器
|
// 请求拦截器
|
||||||
request.interceptors.request.use(
|
request.interceptors.request.use(
|
||||||
(config: CustomAxiosRequestConfig) => {
|
(config: CustomAxiosRequestConfig) => {
|
||||||
// 初始化重试次数
|
getSetData();
|
||||||
config.retryCount = 0;
|
// 只在retryCount未定义时初始化为0
|
||||||
|
if (config.retryCount === undefined) {
|
||||||
|
config.retryCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// 在请求发送之前做一些处理
|
// 在请求发送之前做一些处理
|
||||||
// 在get请求params中添加timestamp
|
// 在get请求params中添加timestamp
|
||||||
if (config.method === 'get') {
|
if (config.method === 'get') {
|
||||||
config.params = {
|
config.params = {
|
||||||
...config.params,
|
...config.params,
|
||||||
timestamp: Date.now()
|
timestamp: Date.now(),
|
||||||
};
|
};
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -42,6 +48,16 @@ request.interceptors.request.use(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(isElectron){
|
||||||
|
const proxyConfig = setData?.proxyConfig
|
||||||
|
if (proxyConfig?.enable && ['http', 'https'].includes(proxyConfig?.protocol)) {
|
||||||
|
config.params.proxy = `${proxyConfig.protocol}://${proxyConfig.host}:${proxyConfig.port}`
|
||||||
|
}
|
||||||
|
if(setData.enableRealIP && setData.realIP){
|
||||||
|
config.params.realIP = setData.realIP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
},
|
},
|
||||||
(error) => {
|
(error) => {
|
||||||
@@ -58,14 +74,15 @@ request.interceptors.response.use(
|
|||||||
async (error) => {
|
async (error) => {
|
||||||
const config = error.config as CustomAxiosRequestConfig;
|
const config = error.config as CustomAxiosRequestConfig;
|
||||||
|
|
||||||
// 如果没有配置重试次数,则初始化为0
|
// 如果没有配置,直接返回错误
|
||||||
if (!config || !config.retryCount) {
|
if (!config) {
|
||||||
config.retryCount = 0;
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否还可以重试
|
// 检查是否还可以重试
|
||||||
if (config.retryCount < MAX_RETRIES) {
|
if (config.retryCount !== undefined && config.retryCount < MAX_RETRIES) {
|
||||||
config.retryCount++;
|
config.retryCount++;
|
||||||
|
console.log(`请求重试第 ${config.retryCount} 次`);
|
||||||
|
|
||||||
// 延迟重试
|
// 延迟重试
|
||||||
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
await new Promise((resolve) => setTimeout(resolve, RETRY_DELAY));
|
||||||
@@ -74,6 +91,7 @@ request.interceptors.response.use(
|
|||||||
return request(config);
|
return request(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log(`重试${MAX_RETRIES}次后仍然失败`);
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -126,7 +126,7 @@
|
|||||||
{ label: '最小化到托盘', value: 'minimize' },
|
{ label: '最小化到托盘', value: 'minimize' },
|
||||||
{ label: '直接退出', value: 'close' }
|
{ label: '直接退出', value: 'close' }
|
||||||
]"
|
]"
|
||||||
style="width: 120px"
|
style="width: 160px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="set-item" v-if="isElectron">
|
<div class="set-item" v-if="isElectron">
|
||||||
@@ -136,15 +136,84 @@
|
|||||||
</div>
|
</div>
|
||||||
<n-button type="primary" @click="restartApp">重启</n-button>
|
<n-button type="primary" @click="restartApp">重启</n-button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="set-item" v-if="isElectron">
|
||||||
|
<div>
|
||||||
|
<div class="set-item-title">代理设置</div>
|
||||||
|
<div class="set-item-content">无法访问音乐时可以开启代理</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<n-switch v-model:value="setData.proxyConfig.enable">
|
||||||
|
<template #checked>开启</template>
|
||||||
|
<template #unchecked>关闭</template>
|
||||||
|
</n-switch>
|
||||||
|
<n-button size="small" @click="showProxyModal = true">配置</n-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="set-item" v-if="isElectron">
|
||||||
|
<div>
|
||||||
|
<div class="set-item-title">realIP</div>
|
||||||
|
<div class="set-item-content">由于限制,此项目在国外使用会受到限制可使用realIP参数,传进国内IP解决,如:116.25.146.177 即可解决</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<n-switch v-model:value="setData.enableRealIP">
|
||||||
|
<template #checked>开启</template>
|
||||||
|
<template #unchecked>关闭</template>
|
||||||
|
</n-switch>
|
||||||
|
<n-input
|
||||||
|
v-if="setData.enableRealIP"
|
||||||
|
v-model:value="setData.realIP"
|
||||||
|
placeholder="realIP"
|
||||||
|
@blur="validateAndSaveRealIP"
|
||||||
|
style="width: 200px"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PlayBottom/>
|
<PlayBottom/>
|
||||||
|
<n-modal
|
||||||
|
v-model:show="showProxyModal"
|
||||||
|
preset="dialog"
|
||||||
|
title="代理设置"
|
||||||
|
positive-text="确认"
|
||||||
|
negative-text="取消"
|
||||||
|
@positive-click="handleProxyConfirm"
|
||||||
|
@negative-click="showProxyModal = false"
|
||||||
|
:show-icon="false"
|
||||||
|
>
|
||||||
|
<n-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="proxyForm"
|
||||||
|
:rules="proxyRules"
|
||||||
|
label-placement="left"
|
||||||
|
label-width="80"
|
||||||
|
require-mark-placement="right-hanging"
|
||||||
|
>
|
||||||
|
<n-form-item label="代理协议" path="protocol">
|
||||||
|
<n-select
|
||||||
|
v-model:value="proxyForm.protocol"
|
||||||
|
:options="[
|
||||||
|
{ label: 'HTTP', value: 'http' },
|
||||||
|
{ label: 'HTTPS', value: 'https' },
|
||||||
|
{ label: 'SOCKS5', value: 'socks5' }
|
||||||
|
]"
|
||||||
|
/>
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="代理地址" path="host">
|
||||||
|
<n-input v-model:value="proxyForm.host" placeholder="请输入代理地址" />
|
||||||
|
</n-form-item>
|
||||||
|
<n-form-item label="代理端口" path="port">
|
||||||
|
<n-input-number v-model:value="proxyForm.port" placeholder="请输入代理端口" :min="1" :max="65535" />
|
||||||
|
</n-form-item>
|
||||||
|
</n-form>
|
||||||
|
</n-modal>
|
||||||
</n-scrollbar>
|
</n-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, ref, onMounted } from 'vue';
|
import { computed, ref, onMounted, watch } from 'vue';
|
||||||
import { useStore } from 'vuex';
|
import { useStore } from 'vuex';
|
||||||
import { useMessage } from 'naive-ui';
|
import { useMessage } from 'naive-ui';
|
||||||
|
import type { FormRules } from 'naive-ui';
|
||||||
import { isElectron } from '@/utils';
|
import { isElectron } from '@/utils';
|
||||||
import { checkUpdate, UpdateResult } from '@/utils/update';
|
import { checkUpdate, UpdateResult } from '@/utils/update';
|
||||||
import { selectDirectory, openDirectory } from '@/utils/fileOperation';
|
import { selectDirectory, openDirectory } from '@/utils/fileOperation';
|
||||||
@@ -167,7 +236,19 @@ const closeActionLabels = {
|
|||||||
close: '直接退出'
|
close: '直接退出'
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
const setData = computed(() => store.state.setData);
|
const setData = computed(() => {
|
||||||
|
const data = store.state.setData;
|
||||||
|
// 确保代理配置存在
|
||||||
|
if (!data.proxyConfig) {
|
||||||
|
data.proxyConfig = {
|
||||||
|
enable: false,
|
||||||
|
protocol: 'http',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7890
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
|
||||||
watch(() => setData.value, (newVal) => {
|
watch(() => setData.value, (newVal) => {
|
||||||
store.commit('setSetData', newVal)
|
store.commit('setSetData', newVal)
|
||||||
@@ -226,8 +307,116 @@ const openDownloadPath = () => {
|
|||||||
openDirectory(setData.value.downloadPath, message);
|
openDirectory(setData.value.downloadPath, message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const showProxyModal = ref(false);
|
||||||
|
const formRef = ref();
|
||||||
|
const proxyForm = ref({
|
||||||
|
protocol: 'http',
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 7890
|
||||||
|
});
|
||||||
|
|
||||||
|
const proxyRules: FormRules = {
|
||||||
|
protocol: {
|
||||||
|
required: true,
|
||||||
|
message: '请选择代理协议',
|
||||||
|
trigger: ['blur', 'change']
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入代理地址',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
validator: (_rule, value) => {
|
||||||
|
if (!value) return false;
|
||||||
|
// 简单的IP或域名验证
|
||||||
|
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$|^localhost$|^[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/;
|
||||||
|
return ipRegex.test(value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
required: true,
|
||||||
|
message: '请输入有效的端口号(1-65535)',
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
|
validator: (_rule, value) => {
|
||||||
|
return value >= 1 && value <= 65535;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化时从store获取代理配置
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
checkForUpdates();
|
checkForUpdates();
|
||||||
|
if (setData.value.proxyConfig) {
|
||||||
|
proxyForm.value = { ...setData.value.proxyConfig };
|
||||||
|
}
|
||||||
|
// 确保enableRealIP有默认值
|
||||||
|
if (setData.value.enableRealIP === undefined) {
|
||||||
|
store.commit('setSetData', {
|
||||||
|
...setData.value,
|
||||||
|
enableRealIP: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 监听代理配置变化
|
||||||
|
watch(() => setData.value.proxyConfig, (newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
proxyForm.value = {
|
||||||
|
protocol: newVal.protocol || 'http',
|
||||||
|
host: newVal.host || '127.0.0.1',
|
||||||
|
port: newVal.port || 7890
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, { immediate: true, deep: true });
|
||||||
|
|
||||||
|
const handleProxyConfirm = async () => {
|
||||||
|
try {
|
||||||
|
await formRef.value?.validate();
|
||||||
|
// 保存代理配置时保留enable状态
|
||||||
|
store.commit('setSetData', {
|
||||||
|
...setData.value,
|
||||||
|
proxyConfig: {
|
||||||
|
enable: setData.value.proxyConfig?.enable || false,
|
||||||
|
protocol: proxyForm.value.protocol,
|
||||||
|
host: proxyForm.value.host,
|
||||||
|
port: proxyForm.value.port
|
||||||
|
}
|
||||||
|
});
|
||||||
|
showProxyModal.value = false;
|
||||||
|
message.success('代理设置已保存,重启应用后生效');
|
||||||
|
} catch (err) {
|
||||||
|
message.error('请检查输入是否正确');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateAndSaveRealIP = () => {
|
||||||
|
const ipRegex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||||
|
if (!setData.value.realIP || ipRegex.test(setData.value.realIP)) {
|
||||||
|
store.commit('setSetData', {
|
||||||
|
...setData.value,
|
||||||
|
realIP: setData.value.realIP,
|
||||||
|
enableRealIP: true
|
||||||
|
});
|
||||||
|
if (setData.value.realIP) {
|
||||||
|
message.success('真实IP设置已保存');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message.error('请输入有效的IP地址');
|
||||||
|
store.commit('setSetData', {
|
||||||
|
...setData.value,
|
||||||
|
realIP: ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听enableRealIP变化,当关闭时清空realIP
|
||||||
|
watch(() => setData.value.enableRealIP, (newVal) => {
|
||||||
|
if (!newVal) {
|
||||||
|
store.commit('setSetData', {
|
||||||
|
...setData.value,
|
||||||
|
realIP: '',
|
||||||
|
enableRealIP: false
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user