mirror of
https://github.com/pompurin404/mihomo-party.git
synced 2024-11-16 11:42:19 +08:00
support deeplink
This commit is contained in:
parent
2e194e9d35
commit
2eb3370df7
|
@ -14,6 +14,11 @@ asarUnpack:
|
|||
extraResources:
|
||||
- from: './resources/'
|
||||
to: ''
|
||||
protocols:
|
||||
name: 'Mihomo Party URI Scheme'
|
||||
schemes:
|
||||
- 'clash'
|
||||
- 'mihomo'
|
||||
win:
|
||||
target:
|
||||
- nsis
|
||||
|
@ -41,6 +46,8 @@ mac:
|
|||
dmg:
|
||||
artifactName: ${name}-macos-${version}-${arch}-installer.${ext}
|
||||
linux:
|
||||
desktop:
|
||||
MimeType: 'x-scheme-handler/clash;x-scheme-handler/mihomo'
|
||||
target:
|
||||
- deb
|
||||
- rpm
|
||||
|
|
|
@ -6,6 +6,7 @@ import { window } from '..'
|
|||
import axios from 'axios'
|
||||
import yaml from 'yaml'
|
||||
import fs from 'fs'
|
||||
import { dialog } from 'electron'
|
||||
|
||||
let profileConfig: IProfileConfig // profile.yaml
|
||||
let currentProfile: Partial<IMihomoConfig> // profiles/xxx.yaml
|
||||
|
@ -95,6 +96,10 @@ export async function createProfile(item: Partial<IProfileItem>): Promise<IProfi
|
|||
switch (newItem.type) {
|
||||
case 'remote': {
|
||||
if (!item.url) {
|
||||
dialog.showErrorBox(
|
||||
'URL is required for remote profile',
|
||||
'URL is required for remote profile'
|
||||
)
|
||||
throw new Error('URL is required for remote profile')
|
||||
}
|
||||
try {
|
||||
|
@ -126,12 +131,17 @@ export async function createProfile(item: Partial<IProfileItem>): Promise<IProfi
|
|||
}
|
||||
fs.writeFileSync(profilePath(id), data, 'utf-8')
|
||||
} catch (e) {
|
||||
dialog.showErrorBox('Failed to fetch remote profile', `${e}\nurl: ${item.url}`)
|
||||
throw new Error(`Failed to fetch remote profile ${e}`)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'local': {
|
||||
if (!item.file) {
|
||||
dialog.showErrorBox(
|
||||
'File is required for local profile',
|
||||
'File is required for local profile'
|
||||
)
|
||||
throw new Error('File is required for local profile')
|
||||
}
|
||||
const data = item.file
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
} from '../utils/dirs'
|
||||
import { generateProfile } from '../resolve/factory'
|
||||
import { getAppConfig, setAppConfig } from '../config'
|
||||
import { safeStorage } from 'electron'
|
||||
import { dialog, safeStorage } from 'electron'
|
||||
import fs from 'fs'
|
||||
|
||||
let child: ChildProcess
|
||||
|
@ -51,7 +51,12 @@ export function restartCore(): void {
|
|||
|
||||
export function checkProfile(): void {
|
||||
const corePath = mihomoCorePath(getAppConfig().core ?? 'mihomo')
|
||||
execFileSync(corePath, ['-t', '-f', mihomoWorkConfigPath(), '-d', mihomoTestDir()])
|
||||
try {
|
||||
execFileSync(corePath, ['-t', '-f', mihomoWorkConfigPath(), '-d', mihomoTestDir()])
|
||||
} catch (e) {
|
||||
dialog.showErrorBox('Profile check failed', `${e}`)
|
||||
throw new Error('Profile check failed')
|
||||
}
|
||||
}
|
||||
|
||||
export function grantCorePermition(corePath: string): void {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { triggerSysProxy } from './resolve/sysproxy'
|
|||
import icon from '../../resources/icon.png?asset'
|
||||
import { createTray } from './core/tray'
|
||||
import { init } from './resolve/init'
|
||||
import { getAppConfig } from './config'
|
||||
import { addProfileItem, getAppConfig } from './config'
|
||||
import { join } from 'path'
|
||||
import {
|
||||
startMihomoMemory,
|
||||
|
@ -23,11 +23,19 @@ if (!gotTheLock) {
|
|||
app.quit()
|
||||
} else {
|
||||
init()
|
||||
app.on('second-instance', () => {
|
||||
app.on('second-instance', (_event, commandline) => {
|
||||
window?.show()
|
||||
window?.focusOnWebView()
|
||||
const url = commandline.pop()
|
||||
if (url) {
|
||||
handleDeepLink(url)
|
||||
}
|
||||
})
|
||||
app.on('open-url', (_event, url) => {
|
||||
window?.show()
|
||||
window?.focusOnWebView()
|
||||
handleDeepLink(url)
|
||||
})
|
||||
|
||||
// Quit when all windows are closed, except on macOS. There, it's common
|
||||
// for applications and their menu bar to stay active until the user quits
|
||||
// explicitly with Cmd + Q.
|
||||
|
@ -67,6 +75,27 @@ if (!gotTheLock) {
|
|||
})
|
||||
}
|
||||
|
||||
function handleDeepLink(url: string): void {
|
||||
if (url.startsWith('clash://install-config')) {
|
||||
url = url.replace('clash://install-config/?url=', '').replace('clash://install-config?url=', '')
|
||||
addProfileItem({
|
||||
type: 'remote',
|
||||
name: 'Remote File',
|
||||
url
|
||||
})
|
||||
}
|
||||
if (url.startsWith('mihomo://install-config')) {
|
||||
url = url
|
||||
.replace('mihomo://install-config/?url=', '')
|
||||
.replace('mihomo://install-config?url=', '')
|
||||
addProfileItem({
|
||||
type: 'remote',
|
||||
name: 'Remote File',
|
||||
url
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createWindow(): void {
|
||||
// Create the browser window.
|
||||
window = new BrowserWindow({
|
||||
|
|
|
@ -22,6 +22,7 @@ import path from 'path'
|
|||
import { startPacServer } from './server'
|
||||
import { triggerSysProxy } from './sysproxy'
|
||||
import { getAppConfig } from '../config'
|
||||
import { app } from 'electron'
|
||||
|
||||
function initDirs(): void {
|
||||
if (!fs.existsSync(dataDir)) {
|
||||
|
@ -71,10 +72,21 @@ function initFiles(): void {
|
|||
}
|
||||
}
|
||||
|
||||
function initDeeplink(): void {
|
||||
if (process.defaultApp) {
|
||||
if (process.argv.length >= 2) {
|
||||
app.setAsDefaultProtocolClient('clash', process.execPath, [path.resolve(process.argv[1])])
|
||||
}
|
||||
} else {
|
||||
app.setAsDefaultProtocolClient('clash')
|
||||
}
|
||||
}
|
||||
|
||||
export function init(): void {
|
||||
initDirs()
|
||||
initConfig()
|
||||
initFiles()
|
||||
initDeeplink()
|
||||
startPacServer().then(() => {
|
||||
triggerSysProxy(getAppConfig().sysProxy.enable)
|
||||
})
|
||||
|
|
|
@ -59,5 +59,6 @@ export function registerIpcMainHandlers(): void {
|
|||
ipcMain.handle('triggerSysProxy', (_e, enable) => triggerSysProxy(enable))
|
||||
ipcMain.handle('isEncryptionAvailable', isEncryptionAvailable)
|
||||
ipcMain.handle('encryptString', (_e, str) => safeStorage.encryptString(str))
|
||||
ipcMain.handle('platform', () => process.platform)
|
||||
ipcMain.handle('quitApp', () => app.quit())
|
||||
}
|
||||
|
|
|
@ -3,7 +3,12 @@ import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-c
|
|||
import BorderSwitch from '@renderer/components/base/border-swtich'
|
||||
import { TbDeviceIpadHorizontalBolt } from 'react-icons/tb'
|
||||
import { useLocation, useNavigate } from 'react-router-dom'
|
||||
import { encryptString, patchMihomoConfig, isEncryptionAvailable } from '@renderer/utils/ipc'
|
||||
import {
|
||||
platform,
|
||||
encryptString,
|
||||
patchMihomoConfig,
|
||||
isEncryptionAvailable
|
||||
} from '@renderer/utils/ipc'
|
||||
import React, { useState } from 'react'
|
||||
import { useAppConfig } from '@renderer/hooks/use-app-config'
|
||||
import BasePasswordModal from '../base/base-password-modal'
|
||||
|
@ -19,14 +24,17 @@ const TunSwitcher: React.FC = () => {
|
|||
const { enable } = tun || {}
|
||||
|
||||
const onChange = async (enable: boolean): Promise<void> => {
|
||||
const encryptionAvailable = await isEncryptionAvailable()
|
||||
if (!appConfig?.encryptedPassword && encryptionAvailable) {
|
||||
setOpenPasswordModal(true)
|
||||
return
|
||||
}
|
||||
if (!encryptionAvailable) {
|
||||
alert('加密不可用,请手动给内核授权')
|
||||
if (enable && (await platform()) !== 'win32') {
|
||||
const encryptionAvailable = await isEncryptionAvailable()
|
||||
if (!appConfig?.encryptedPassword && encryptionAvailable) {
|
||||
setOpenPasswordModal(true)
|
||||
return
|
||||
}
|
||||
if (!encryptionAvailable) {
|
||||
alert('加密不可用,请手动给内核授权')
|
||||
}
|
||||
}
|
||||
|
||||
await patchControledMihomoConfig({ tun: { enable } })
|
||||
await patchMihomoConfig({ tun: { enable } })
|
||||
}
|
||||
|
|
|
@ -113,6 +113,11 @@ export async function isEncryptionAvailable(): Promise<boolean> {
|
|||
export async function encryptString(str: string): Promise<Buffer> {
|
||||
return await window.electron.ipcRenderer.invoke('encryptString', str)
|
||||
}
|
||||
|
||||
export async function platform(): Promise<NodeJS.Platform> {
|
||||
return await window.electron.ipcRenderer.invoke('platform')
|
||||
}
|
||||
|
||||
export async function quitApp(): Promise<void> {
|
||||
return await window.electron.ipcRenderer.invoke('quitApp')
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user