mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2024-11-14 18:57:40 +01:00
fix: 🐛 修复安装路径包含空格会导致无法启动服务的问题
This commit is contained in:
parent
217d82d03e
commit
29ae786768
15
.vscode/settings.json
vendored
15
.vscode/settings.json
vendored
@ -30,9 +30,16 @@
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"i18n-ally.localesPaths": [
|
||||
"src/locales",
|
||||
"dist-release/win-arm64-unpacked/locales",
|
||||
"dist-release/win-unpacked/locales"
|
||||
"src/locales/index.js",
|
||||
"src/locales/languages"
|
||||
],
|
||||
"i18n-ally.sourceLanguage": "zh"
|
||||
"i18n-ally.sourceLanguage": "zh",
|
||||
"i18n-ally.keystyle": "nested",
|
||||
"i18n-ally.extract.ignored": [
|
||||
"${item.id}(${item.$name}${\r\n item.$remark ? `,${item.$remark}` : ''\r\n })",
|
||||
",${item.$remark}",
|
||||
"${row.$remark ? `${row.$remark}-` : ''}${\r\n row.$name\r\n }-${this.$replaceIP(row.id)}-recording-${dayjs().format(\r\n 'YYYY-MM-DD-HH-mm-ss',\r\n )}.${recordFormat}",
|
||||
"--serial=${row.id} --window-title=${\r\n row.$remark ? `${row.$remark}-` : ''\r\n }${row.$name}-${\r\n row.id\r\n }-🎥录制中... --record=${savePath} ${this.scrcpyArgs(row.id)}",
|
||||
"--serial=${row.id} --window-title=${\r\n row.$remark ? `${row.$remark}-` : ''\r\n }${row.$name}-${row.id} ${this.scrcpyArgs(row.id)}"
|
||||
]
|
||||
}
|
||||
|
@ -26,5 +26,7 @@ export const scrcpyPath
|
||||
? extraResolve('core/scrcpy.exe')
|
||||
: which.sync('scrcpy', { nothrow: true })
|
||||
|
||||
export const logPath = process.env.LOG_PATH
|
||||
|
||||
// console.log('adbPath', adbPath)
|
||||
// console.log('scrcpyPath', scrcpyPath)
|
||||
|
@ -6,6 +6,7 @@ import dayjs from 'dayjs'
|
||||
import { Adb } from '@devicefarmer/adbkit'
|
||||
import appStore from '@electron/helpers/store.js'
|
||||
import { adbPath } from '@electron/configs/index.js'
|
||||
import { uniq } from 'lodash-es'
|
||||
|
||||
const exec = util.promisify(child_process.exec)
|
||||
|
||||
@ -38,7 +39,10 @@ appStore.onDidChange('scrcpy.global.adbPath', async (value, oldValue) => {
|
||||
|
||||
const shell = async command => exec(`${adbPath} ${command}`)
|
||||
const getDevices = async () => client.listDevicesWithPaths()
|
||||
const deviceShell = async (id, command) => client.getDevice(id).shell(command)
|
||||
const deviceShell = async (id, command) => {
|
||||
const res = await client.getDevice(id).shell(command).then(Adb.util.readAll)
|
||||
return res.toString()
|
||||
}
|
||||
const kill = async (...params) => client.kill(...params)
|
||||
const connect = async (...params) => client.connect(...params)
|
||||
const disconnect = async (...params) => client.disconnect(...params)
|
||||
@ -95,6 +99,28 @@ const install = async (id, path) => client.getDevice(id).install(path)
|
||||
|
||||
const version = async () => client.version()
|
||||
|
||||
const display = async (deviceId) => {
|
||||
let value = []
|
||||
try {
|
||||
const res = await deviceShell(deviceId, 'dumpsys display')
|
||||
|
||||
const regex = /Display Id=(\d+)/g
|
||||
|
||||
const match = res.match(regex) || []
|
||||
|
||||
const mapValue = match.map(item => item.split('=')[1])
|
||||
|
||||
value = uniq(mapValue)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error?.message || error)
|
||||
}
|
||||
|
||||
console.log('display.deviceId.value', value)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
const watch = async (callback) => {
|
||||
const tracker = await client.trackDevices()
|
||||
tracker.on('add', async (ret) => {
|
||||
@ -140,6 +166,7 @@ export default () => {
|
||||
screencap,
|
||||
install,
|
||||
version,
|
||||
display,
|
||||
watch,
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
import path from 'node:path'
|
||||
|
||||
import log from '@electron/helpers/log.js'
|
||||
import '@electron/helpers/console.js'
|
||||
|
||||
import store from '@electron/helpers/store.js'
|
||||
import * as configs from '@electron/configs/index.js'
|
||||
|
||||
import electron from './electron/index.js'
|
||||
import adbkit from './adbkit/index.js'
|
||||
import scrcpy from './scrcpy/index.js'
|
||||
@ -12,12 +16,14 @@ export default {
|
||||
|
||||
expose('appStore', store)
|
||||
|
||||
expose('appLog', log)
|
||||
|
||||
expose('electron', {
|
||||
...electron(),
|
||||
configs,
|
||||
})
|
||||
|
||||
expose('adbkit', adbkit())
|
||||
expose('scrcpy', scrcpy())
|
||||
expose('adbkit', adbkit({ log }))
|
||||
expose('scrcpy', scrcpy({ log }))
|
||||
},
|
||||
}
|
||||
|
12
electron/exposes/log/index.js
Normal file
12
electron/exposes/log/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
import log from 'electron-log/main'
|
||||
import { createProxy } from '@electron/helpers/index'
|
||||
|
||||
const levels = Object.keys(log.functions)
|
||||
|
||||
const functions = () => ({ ...createProxy(log, levels) })
|
||||
|
||||
export default {
|
||||
levels,
|
||||
functions: functions(),
|
||||
...functions(),
|
||||
}
|
@ -7,9 +7,10 @@ const shell = async (command, { stdout, stderr } = {}) => {
|
||||
const ADB = appStore.get('scrcpy.global.adbPath') || adbPath
|
||||
const args = command.split(' ')
|
||||
|
||||
const scrcpyProcess = spawn(spawnPath, args, {
|
||||
env: { ...process.env, ADB },
|
||||
const scrcpyProcess = spawn(`"${spawnPath}"`, args, {
|
||||
env: { ...process.env, ADB: `"${ADB}"` },
|
||||
shell: true,
|
||||
encoding: 'utf8',
|
||||
})
|
||||
|
||||
scrcpyProcess.stdout.on('data', (data) => {
|
||||
|
8
electron/helpers/console.js
Normal file
8
electron/helpers/console.js
Normal file
@ -0,0 +1,8 @@
|
||||
import log from '@electron/helpers/log.js'
|
||||
|
||||
import { createProxy } from './index.js'
|
||||
|
||||
Object.assign(console, {
|
||||
...createProxy(log.functions, log.levels),
|
||||
raw: console.log,
|
||||
})
|
@ -1,5 +1,6 @@
|
||||
import { resolve } from 'node:path'
|
||||
import { contextBridge } from 'electron'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
export const isPackaged = process.env.IS_PACKAGED === 'true'
|
||||
|
||||
@ -35,7 +36,8 @@ export function exposeContext(key, value) {
|
||||
*/
|
||||
export function createProxy(targetObject, methodNames) {
|
||||
return methodNames.reduce((proxyObj, methodName) => {
|
||||
proxyObj[methodName] = (...args) => targetObject[methodName](...args)
|
||||
proxyObj[methodName] = (...args) =>
|
||||
targetObject[methodName](...cloneDeep(args))
|
||||
|
||||
return proxyObj
|
||||
}, {})
|
||||
|
19
electron/helpers/log.js
Normal file
19
electron/helpers/log.js
Normal file
@ -0,0 +1,19 @@
|
||||
import { shell } from 'electron'
|
||||
import log from 'electron-log/main'
|
||||
import { createProxy } from '@electron/helpers/index'
|
||||
|
||||
log.transports.console.level = false
|
||||
|
||||
const levels = Object.keys(log.functions)
|
||||
|
||||
const getFilePath = () => log.transports.file.getFile()?.path
|
||||
|
||||
console.log('logPath', getFilePath())
|
||||
|
||||
export default {
|
||||
...createProxy(log, ['initialize', ...levels]),
|
||||
levels,
|
||||
functions: createProxy(log, levels),
|
||||
getFilePath,
|
||||
openInEditor: () => shell.openPath(getFilePath()),
|
||||
}
|
@ -1,11 +1,17 @@
|
||||
import Store from 'electron-store'
|
||||
import { isEqual } from 'lodash-es'
|
||||
import { createProxy } from './index.js'
|
||||
|
||||
const appStore = new Store()
|
||||
|
||||
appStore.onDidAnyChange((value) => {
|
||||
console.log('appStore.onDidAnyChange.value', value)
|
||||
})
|
||||
// appStore.onDidAnyChange((value) => {
|
||||
// console.log('appStore.onDidAnyChange.value', value)
|
||||
// })
|
||||
|
||||
// 如果没有数据则手动设置值,以保证配置文件生成成功
|
||||
if (isEqual(appStore.store, {})) {
|
||||
appStore.store = {}
|
||||
}
|
||||
|
||||
export default {
|
||||
...createProxy(appStore, [
|
||||
|
@ -6,10 +6,17 @@ import { electronApp, optimizer } from '@electron-toolkit/utils'
|
||||
import './helpers/process.js'
|
||||
import './helpers/store.js'
|
||||
|
||||
import log from './helpers/log.js'
|
||||
import './helpers/console.js'
|
||||
|
||||
import { icnsLogoPath, icoLogoPath, logoPath } from './configs/index.js'
|
||||
|
||||
import events from './events/index.js'
|
||||
|
||||
log.initialize({ preload: true })
|
||||
|
||||
console.log('Successfully initialized the Escrcpy logging system.')
|
||||
|
||||
// The built directory structure
|
||||
//
|
||||
// ├─┬─┬ dist
|
||||
|
@ -33,6 +33,7 @@
|
||||
"dayjs": "^1.11.10",
|
||||
"electron": "^27.0.2",
|
||||
"electron-builder": "^24.6.4",
|
||||
"electron-log": "^5.0.0",
|
||||
"electron-store": "^8.1.0",
|
||||
"electron-updater": "^6.1.4",
|
||||
"element-plus": "^2.4.0",
|
||||
|
@ -30,7 +30,7 @@
|
||||
:loading="connectLoading"
|
||||
@click="handleConnect"
|
||||
>
|
||||
{{ $t("devices.wireless.connect") }}
|
||||
{{ $t("devices.wireless.connect.name") }}
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
@ -38,10 +38,13 @@
|
||||
:loading="loading"
|
||||
@click="handleRefresh"
|
||||
>
|
||||
{{ $t("devices.refresh") }}
|
||||
{{ $t("devices.refresh.name") }}
|
||||
</el-button>
|
||||
<el-button type="warning" icon="RefreshRight" @click="handleRestart">
|
||||
{{ $t("devices.restart") }}
|
||||
{{ $t("devices.restart.name") }}
|
||||
</el-button>
|
||||
<el-button icon="View" @click="handleLog">
|
||||
{{ $t("devices.log.name") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="pt-4 flex-1 h-0 overflow-hidden">
|
||||
@ -74,7 +77,7 @@
|
||||
<div class="flex items-center">
|
||||
<el-tooltip
|
||||
v-if="row.$unauthorized"
|
||||
content="设备可能未授权成功,请重新插拔设备并点击允许USB调试"
|
||||
:content="$t('devices.device.permission.error')"
|
||||
placement="top-start"
|
||||
>
|
||||
<el-icon class="mr-1 text-red-600 text-lg">
|
||||
@ -110,8 +113,8 @@
|
||||
>
|
||||
{{
|
||||
row.$loading
|
||||
? $t("devices.operates.mirroring")
|
||||
: $t("devices.operates.mirror")
|
||||
? $t("devices.mirror.progress")
|
||||
: $t("devices.mirror.start")
|
||||
}}
|
||||
</el-button>
|
||||
|
||||
@ -125,8 +128,8 @@
|
||||
>
|
||||
{{
|
||||
row.$recordLoading
|
||||
? $t("devices.operates.recording")
|
||||
: $t("devices.operates.record")
|
||||
? $t("devices.record.progress")
|
||||
: $t("devices.record.start")
|
||||
}}
|
||||
</el-button>
|
||||
|
||||
@ -142,7 +145,7 @@
|
||||
<template #icon>
|
||||
<svg-icon name="wifi"></svg-icon>
|
||||
</template>
|
||||
{{ $t("devices.operates.wireless") }}
|
||||
{{ $t("devices.wireless.mode") }}
|
||||
</el-button>
|
||||
|
||||
<el-button
|
||||
@ -156,8 +159,8 @@
|
||||
>
|
||||
{{
|
||||
row.$stopLoading
|
||||
? $t("devices.operates.disconnecting")
|
||||
: $t("devices.operates.disconnect")
|
||||
? $t("devices.wireless.disconnect.progress")
|
||||
: $t("devices.wireless.disconnect.start")
|
||||
}}
|
||||
</el-button>
|
||||
</template>
|
||||
@ -243,21 +246,24 @@ export default {
|
||||
try {
|
||||
await this.$confirm(
|
||||
`
|
||||
<div>通常情况下,这可能是因为更新 Escrcpy 后,缓存的依赖配置不兼容所导致的,是否重置依赖配置?</div>
|
||||
<div class="text-red-500">注意:重置后,之前保存的依赖配置将会被清除,因此建议在执行重置操作之前备份您的配置。</div>
|
||||
<div>${this.$t('devices.reset.reasons[0]')}</div>
|
||||
<div class="text-red-500">${this.$t('devices.reset.reasons[1]')}</div>
|
||||
`,
|
||||
'操作失败',
|
||||
this.$t('devices.reset.title'),
|
||||
{
|
||||
dangerouslyUseHTMLString: true,
|
||||
confirmButtonText: '重置依赖配置',
|
||||
cancelButtonText: '取消',
|
||||
confirmButtonText: this.$t('devices.reset.confirm'),
|
||||
cancelButtonText: this.$t('devices.reset.cancel'),
|
||||
closeOnClickModal: false,
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
|
||||
this.$store.scrcpy.resetDeps(depType)
|
||||
|
||||
this.$root.reRender('Preference')
|
||||
this.$message.success('操作成功,请重新尝试。')
|
||||
|
||||
this.$message.success(this.$t('devices.reset.success'))
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message) {
|
||||
@ -294,20 +300,24 @@ export default {
|
||||
try {
|
||||
const command = `--serial=${row.id} --window-title=${
|
||||
row.$remark ? `${row.$remark}-` : ''
|
||||
}${row.$name}-${
|
||||
row.id
|
||||
}-🎥录制中... --record=${savePath} ${this.scrcpyArgs(row.id)}`
|
||||
}${row.$name}-${row.id}-🎥${this.$t(
|
||||
'devices.record.progress',
|
||||
)}... --record=${savePath} ${this.scrcpyArgs(row.id)}`
|
||||
|
||||
console.log('handleRecord.command', command)
|
||||
|
||||
await this.$scrcpy.shell(command, { stdout: this.onStdout })
|
||||
|
||||
await this.$confirm('是否前往录制位置进行查看?', '录制成功', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'success',
|
||||
})
|
||||
await this.$confirm(
|
||||
this.$t('devices.record.success.message'),
|
||||
this.$t('devices.record.success.title'),
|
||||
{
|
||||
confirmButtonText: this.$t('common.confirm'),
|
||||
cancelButtonText: this.$t('common.cancel'),
|
||||
closeOnClickModal: false,
|
||||
type: 'success',
|
||||
},
|
||||
)
|
||||
|
||||
await this.$electron.ipcRenderer.invoke(
|
||||
'show-item-in-folder',
|
||||
@ -365,16 +375,21 @@ export default {
|
||||
handleRestart() {
|
||||
this.$electron.ipcRenderer.send('restart-app')
|
||||
},
|
||||
handleLog() {
|
||||
this.$appLog.openInEditor()
|
||||
},
|
||||
async handleConnect() {
|
||||
if (!this.formData.host) {
|
||||
this.$message.warning('无线调试地址不能为空')
|
||||
this.$message.warning(
|
||||
this.$t('devices.wireless.connect.error.no-address'),
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
this.connectLoading = true
|
||||
try {
|
||||
await this.$adb.connect(this.formData.host, this.formData.port || 5555)
|
||||
this.$message.success('连接设备成功')
|
||||
this.$message.success(this.$t('devices.wireless.connect.success'))
|
||||
storage.set('adbCache', this.formData)
|
||||
}
|
||||
catch (error) {
|
||||
@ -387,21 +402,23 @@ export default {
|
||||
await this.$confirm(
|
||||
`
|
||||
<div class="pb-4 text-sm text-red-500">${this.$t(
|
||||
'devices.wireless.error.detail',
|
||||
'devices.wireless.connect.error.detail',
|
||||
)}:${message}</div>
|
||||
<div>${this.$t('devices.wireless.error.reasons[0]')}:</div>
|
||||
<div>1. ${this.$t('devices.wireless.error.reasons[1]')} </div>
|
||||
<div>2. ${this.$t('devices.wireless.error.reasons[2]')} </div>
|
||||
<div>3. ${this.$t('devices.wireless.error.reasons[3]')} </div>
|
||||
<div>4. ${this.$t('devices.wireless.error.reasons[4]')} </div>
|
||||
<div>5. ${this.$t('devices.wireless.error.reasons[5]')} </div>
|
||||
<div>${this.$t('devices.wireless.connect.error.reasons[0]')}:</div>
|
||||
<div>1. ${this.$t('devices.wireless.connect.error.reasons[1]')} </div>
|
||||
<div>2. ${this.$t('devices.wireless.connect.error.reasons[2]')} </div>
|
||||
<div>3. ${this.$t('devices.wireless.connect.error.reasons[3]')} </div>
|
||||
<div>4. ${this.$t('devices.wireless.connect.error.reasons[4]')} </div>
|
||||
<div>5. ${this.$t('devices.wireless.connect.error.reasons[5]')} </div>
|
||||
`,
|
||||
this.$t('devices.wireless.error.title'),
|
||||
this.$t('devices.wireless.connect.error.title'),
|
||||
{
|
||||
dangerouslyUseHTMLString: true,
|
||||
closeOnClickModal: false,
|
||||
confirmButtonText: this.$t('devices.wireless.error.confirm'),
|
||||
cancelButtonText: this.$t('devices.wireless.error.cancel'),
|
||||
confirmButtonText: this.$t(
|
||||
'devices.wireless.connect.error.confirm',
|
||||
),
|
||||
cancelButtonText: this.$t('devices.wireless.connect.error.cancel'),
|
||||
type: 'warning',
|
||||
},
|
||||
)
|
||||
@ -417,7 +434,7 @@ export default {
|
||||
try {
|
||||
await this.$adb.disconnect(host, port)
|
||||
await sleep()
|
||||
this.$message.success('断开连接成功')
|
||||
this.$message.success(this.$t('devices.wireless.disconnect.success'))
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message)
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<div class="pb-4 pr-2 flex items-center justify-between">
|
||||
<div label="作用域范围">
|
||||
<div class="">
|
||||
<el-select
|
||||
v-model="scopeValue"
|
||||
value-key=""
|
||||
placeholder="偏好设置的作用域范围"
|
||||
:placeholder="$t('preferences.scope.placeholder')"
|
||||
filterable
|
||||
no-data-text="暂无数据"
|
||||
:no-data-text="$t('preferences.scope.no-data')"
|
||||
class="!w-90"
|
||||
@change="onScopeChange"
|
||||
>
|
||||
@ -19,13 +19,13 @@
|
||||
<template #content>
|
||||
<div class="space-y-1">
|
||||
<div class="pb-1">
|
||||
对全局或者单个设备设置不同的偏好配置
|
||||
{{ $t("preferences.scope.details[0]") }}
|
||||
</div>
|
||||
<div class="">
|
||||
全局:将对所有设备生效。
|
||||
{{ $t("preferences.scope.details[1]") }}
|
||||
</div>
|
||||
<div class="">
|
||||
单个设备:继承于全局配置,并对单个设备进行独立设置,仅对此设备生效。
|
||||
{{ $t("preferences.scope.details[2]") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -42,16 +42,16 @@
|
||||
</div>
|
||||
<div class="">
|
||||
<el-button type="" plain @click="handleImport">
|
||||
{{ $t("preferences.config.import") }}
|
||||
{{ $t("preferences.config.import.name") }}
|
||||
</el-button>
|
||||
<el-button type="" plain @click="handleExport">
|
||||
{{ $t("preferences.config.export") }}
|
||||
{{ $t("preferences.config.export.name") }}
|
||||
</el-button>
|
||||
<el-button type="" plain @click="handleEdit">
|
||||
{{ $t("preferences.config.edit") }}
|
||||
{{ $t("preferences.config.edit.name") }}
|
||||
</el-button>
|
||||
<el-button type="" plain @click="handleResetAll">
|
||||
{{ $t("preferences.config.reset") }}
|
||||
{{ $t("preferences.config.reset.name") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@ -78,7 +78,7 @@
|
||||
<el-form
|
||||
ref="elForm"
|
||||
:model="scrcpyForm"
|
||||
label-width="135px"
|
||||
label-width="170px"
|
||||
class="pr-8 pt-4"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
@ -158,6 +158,7 @@
|
||||
clearable
|
||||
:title="item_1.placeholder"
|
||||
></el-switch>
|
||||
|
||||
<el-select
|
||||
v-if="item_1.type === 'select'"
|
||||
v-bind="item_1.props || {}"
|
||||
@ -238,7 +239,7 @@ export default {
|
||||
}))
|
||||
|
||||
value.unshift({
|
||||
label: `Global(${this.$t('preferences.global')})`,
|
||||
label: `Global(${this.$t('preferences.scope.global')})`,
|
||||
value: 'global',
|
||||
})
|
||||
|
||||
@ -252,6 +253,15 @@ export default {
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
scopeValue: {
|
||||
handler(value) {
|
||||
if (value === 'global') {
|
||||
return
|
||||
}
|
||||
this.getDisplay(value)
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.handleSave = debounce(this.handleSave, 1000, {
|
||||
@ -269,15 +279,27 @@ export default {
|
||||
this.$store.scrcpy.setScope(replaceIPValue)
|
||||
this.scrcpyForm = this.$store.scrcpy.config
|
||||
},
|
||||
async getDisplay(value) {
|
||||
const display = await this.$adb.display(value)
|
||||
|
||||
console.log('display', display)
|
||||
|
||||
this.$store.scrcpy.setModel('video', { display })
|
||||
},
|
||||
async handleImport() {
|
||||
try {
|
||||
await this.$electron.ipcRenderer.invoke('show-open-dialog', {
|
||||
preset: 'replaceFile',
|
||||
filePath: this.$appStore.path,
|
||||
filters: [{ name: '请选择要导入的配置文件', extensions: ['json'] }],
|
||||
filters: [
|
||||
{
|
||||
name: this.$t('preferences.config.import.placeholder'),
|
||||
extensions: ['json'],
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
this.$message.success('导入偏好配置成功')
|
||||
this.$message.success(this.$t('preferences.config.import.success'))
|
||||
|
||||
this.scrcpyForm = this.$store.scrcpy.init()
|
||||
}
|
||||
@ -293,7 +315,7 @@ export default {
|
||||
},
|
||||
async handleExport() {
|
||||
const messageEl = this.$message({
|
||||
message: ' 正在导出偏好配置中...',
|
||||
message: this.$t('preferences.config.export.message'),
|
||||
icon: LoadingIcon,
|
||||
duration: 0,
|
||||
})
|
||||
@ -303,10 +325,13 @@ export default {
|
||||
defaultPath: 'escrcpy-configs.json',
|
||||
filePath: this.$appStore.path,
|
||||
filters: [
|
||||
{ name: '请选择配置文件要保存的位置', extensions: ['json'] },
|
||||
{
|
||||
name: this.$t('preferences.config.export.placeholder'),
|
||||
extensions: ['json'],
|
||||
},
|
||||
],
|
||||
})
|
||||
this.$message.success('导出偏好配置成功')
|
||||
this.$message.success(this.$t('preferences.config.export.success'))
|
||||
}
|
||||
catch (error) {
|
||||
if (error.message) {
|
||||
@ -346,9 +371,10 @@ export default {
|
||||
},
|
||||
handleSave() {
|
||||
this.$store.scrcpy.setConfig(this.scrcpyForm)
|
||||
this.$message.success('保存配置成功,将在下一次控制设备时生效')
|
||||
this.$message.success(this.$t('preferences.config.save.placeholder'))
|
||||
},
|
||||
getSubModel(type) {
|
||||
console.log('getSubModel')
|
||||
const value = this.$store.scrcpy.getModel(type)
|
||||
return value
|
||||
},
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { createI18n } from 'vue-i18n'
|
||||
import messages from '@intlify/unplugin-vue-i18n/messages'
|
||||
|
||||
const locale = window.electron?.process?.env?.LOCALE
|
||||
// const locale = 'en_US'
|
||||
// const locale = window.electron?.process?.env?.LOCALE
|
||||
const locale = 'en_US'
|
||||
|
||||
// console.log('locale', locale)
|
||||
|
||||
|
@ -5,50 +5,77 @@
|
||||
},
|
||||
"devices": {
|
||||
"name": "Devices",
|
||||
|
||||
"loading": "In the loading device...",
|
||||
|
||||
"loading": "Devices loading...",
|
||||
"empty": "No device detected",
|
||||
|
||||
"wireless": {
|
||||
"name": "Wireless",
|
||||
"connect": "Connect",
|
||||
"error": {
|
||||
"title": "Failed to Connect Device",
|
||||
"detail": "Error Details",
|
||||
"reasons": [
|
||||
"Possible reasons:",
|
||||
"Incorrect IP address or port number",
|
||||
"Device pairing unsuccessful",
|
||||
"Computer network and provided device network IP are not in the same LAN",
|
||||
"Incorrect adb dependency path",
|
||||
"Other unknown errors"
|
||||
],
|
||||
"confirm": "Wireless Pairing",
|
||||
"cancel": "@:common.cancel"
|
||||
"mode": "Wireless mode",
|
||||
"connect": {
|
||||
"name": "Connect",
|
||||
"error": {
|
||||
"title": "连接设备失败",
|
||||
"detail": "错误详情",
|
||||
"reasons": [
|
||||
"可能有以下原因",
|
||||
"IP地址或端口号错误",
|
||||
"设备未与当前电脑配对成功",
|
||||
"电脑网络和提供的设备网络IP不在同一个局域网中",
|
||||
"adb 依赖路径错误",
|
||||
"其他未知错误"
|
||||
],
|
||||
"confirm": "无线配对",
|
||||
"cancel": "@:common.cancel",
|
||||
"no-address": "无线调试地址不能为空"
|
||||
},
|
||||
"success": "连接设备成功"
|
||||
},
|
||||
"success": "Device Connected Successfully"
|
||||
"disconnect": {
|
||||
"start": "断开连接",
|
||||
"progress": "正在断开",
|
||||
"success": "断开连接成功"
|
||||
}
|
||||
},
|
||||
"reset": {
|
||||
"title": "操作失败",
|
||||
"reasons": [
|
||||
"通常情况下,这可能是因为更新 Escrcpy 后,缓存的依赖配置不兼容所导致的,是否重置依赖配置?",
|
||||
"注意:重置后,之前保存的依赖配置将会被清除,因此建议在执行重置操作之前备份您的配置。"
|
||||
],
|
||||
"confirm": "重置依赖配置",
|
||||
"cancel": "@:common.cancel",
|
||||
"success": "操作成功,请重新尝试。"
|
||||
},
|
||||
"refresh": {
|
||||
"name": "Refresh"
|
||||
},
|
||||
"restart": {
|
||||
"name": "Restart"
|
||||
},
|
||||
"log": {
|
||||
"name": "Logs"
|
||||
},
|
||||
|
||||
"refresh": "Refresh",
|
||||
"restart": "Restart",
|
||||
|
||||
"device": {
|
||||
"id": "ID",
|
||||
"name": "Name",
|
||||
"remark": "Remark"
|
||||
"remark": "Remark",
|
||||
"permission": {
|
||||
"error": "设备可能未授权成功,请重新插拔设备并点击允许USB调试"
|
||||
}
|
||||
},
|
||||
"mirror": {
|
||||
"start": "Mirror",
|
||||
"progress": "Mirroring"
|
||||
},
|
||||
"record": {
|
||||
"start": "Record",
|
||||
"progress": "Recording",
|
||||
"success": {
|
||||
"title": "录制成功",
|
||||
"message": "是否前往录制位置进行查看?"
|
||||
}
|
||||
},
|
||||
|
||||
"operates": {
|
||||
"name": "Operations",
|
||||
"more": "More",
|
||||
"mirror": "Mirror",
|
||||
"mirroring": "Mirroring",
|
||||
"record": "Record",
|
||||
"recording": "Recording",
|
||||
"wireless": "Wireless Mode",
|
||||
"disconnect": "Disconnect",
|
||||
"disconnecting": "Disconnecting",
|
||||
"install": "Install APP",
|
||||
"capture": "Capture",
|
||||
"reboot": "Reboot",
|
||||
@ -61,97 +88,207 @@
|
||||
},
|
||||
"preferences": {
|
||||
"name": "Preferences",
|
||||
"global": "Global",
|
||||
|
||||
"config": {
|
||||
"import": "Import",
|
||||
"export": "Export",
|
||||
"edit": "Edit",
|
||||
"reset": "Reset"
|
||||
"reset": "Resets",
|
||||
"scope": {
|
||||
"global": "Global",
|
||||
"placeholder": "偏好设置的作用域范围",
|
||||
"no-data": "暂无数据",
|
||||
"details": [
|
||||
"对全局或者单个设备设置不同的偏好配置",
|
||||
"全局:将对所有设备生效。",
|
||||
"单个设备:继承于全局配置,并对单个设备进行独立设置,仅对此设备生效。"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"import": {
|
||||
"name": "导入配置",
|
||||
"placeholder": "请选择要导入的配置文件",
|
||||
"success": "导入成功"
|
||||
},
|
||||
"export": {
|
||||
"name": "导出配置",
|
||||
"message": "导出配置",
|
||||
"placeholder": "请选择要导出的位置",
|
||||
"success": "导出成功"
|
||||
},
|
||||
"edit": {
|
||||
"name": "编辑配置"
|
||||
},
|
||||
"reset": {
|
||||
"name": "重置配置"
|
||||
},
|
||||
"save": {
|
||||
"name": "保存配置",
|
||||
"placeholder": "保存配置成功,将在下一次控制设备时生效"
|
||||
}
|
||||
},
|
||||
|
||||
"custom": {
|
||||
"name": "Custom",
|
||||
"file-path": {
|
||||
"file": {
|
||||
"name": "File Path",
|
||||
"placeholder": "Put on the user desktop by default",
|
||||
"tips": "Screenshots and recorded audio and video exist here"
|
||||
},
|
||||
"adb-path": {
|
||||
"adb": {
|
||||
"name": "ADB Path",
|
||||
"placeholder": "Please set the ADB path",
|
||||
"tips": "The address of the ADB used to connect the device. Note that this option is not affected by the configuration of a single device"
|
||||
},
|
||||
"scrcpy-path": {
|
||||
"scrcpy": {
|
||||
"name": "Scrcpy Path",
|
||||
"placeholder": "Please set the SCRCPY path",
|
||||
"tips": "The address of the SCRCPY used to connect the device. Note that this option is not affected by the configuration of a single device"
|
||||
}
|
||||
},
|
||||
|
||||
"video": {
|
||||
"name": "Video",
|
||||
"resolution": "Resolution",
|
||||
"bit": "Bitrate",
|
||||
"refresh-rate": "Refresh Rate",
|
||||
"decoder": "Video Decoder",
|
||||
"encoder": "Video Encoder",
|
||||
"screen-rotation": "Screen Rotation",
|
||||
"screen-cropping": "Screen Cropping",
|
||||
"multi-display": "Multiple Displays",
|
||||
"video-buffering": "Video Buffering",
|
||||
"audio-buffering": "Audio Buffering",
|
||||
"receiver-buffering": "Receiver Buffering (v412)",
|
||||
"disable": "Disable Video"
|
||||
"resolution": {
|
||||
"name": "Resolution",
|
||||
"placeholder": "Default device resolution",
|
||||
"tips": ""
|
||||
},
|
||||
"bit": {
|
||||
"name": "Bitrate",
|
||||
"placeholder": "Default 4M",
|
||||
"tips": ""
|
||||
},
|
||||
"refresh-rate": {
|
||||
"name": "Refresh Rate",
|
||||
"placeholder": "Default 60",
|
||||
"tips": ""
|
||||
},
|
||||
"decoder": {
|
||||
"name": "Decoder",
|
||||
"placeholder": "Default h264",
|
||||
"tips": ""
|
||||
},
|
||||
"encoder": {
|
||||
"name": "Encoder",
|
||||
"placeholder": "Default device encoder",
|
||||
"tips": ""
|
||||
},
|
||||
"screen-rotation": {
|
||||
"name": "Rotation",
|
||||
"placeholder": "Default device rotation",
|
||||
"tips": ""
|
||||
},
|
||||
"screen-cropping": {
|
||||
"name": "Cropping",
|
||||
"placeholder": "Default no cropping",
|
||||
"tips": ""
|
||||
},
|
||||
"multi-display": {
|
||||
"name": "Multi-Display",
|
||||
"placeholder": "Default 0 (main)",
|
||||
"tips": ""
|
||||
},
|
||||
"video-buffering": {
|
||||
"name": "Video Buffering",
|
||||
"placeholder": "Default 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"audio-buffering": {
|
||||
"name": "Audio Buffering",
|
||||
"placeholder": "Default 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"receiver-buffering": {
|
||||
"name": "Receiver Buffering",
|
||||
"placeholder": "Default 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"disable": {
|
||||
"name": "Disable Video",
|
||||
"placeholder": "Disable video if enabled",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"device": {
|
||||
"name": "Device",
|
||||
"show-touch": "Show Touches",
|
||||
"stay-awake": "Stay Awake",
|
||||
"control-in-close-screen": "Turn Off Screen During Control",
|
||||
"control-end-video": "Turn Off Screen After Control",
|
||||
"control-in-stop-charging": "Stop Charging During Control"
|
||||
"show-touch": {
|
||||
"name": "Show Touches",
|
||||
"placeholder": "Enable to show tap feedback in developer options",
|
||||
"tips": "Only on physical devices"
|
||||
},
|
||||
"stay-awake": {
|
||||
"name": "Stay Awake",
|
||||
"placeholder": "Enable to prevent sleep",
|
||||
"tips": "Wired connection only"
|
||||
},
|
||||
"control-in-close-screen": {
|
||||
"name": "Turn Off Screen",
|
||||
"placeholder": "Automatically turn off screen when controlling device",
|
||||
"tips": ""
|
||||
},
|
||||
"control-end-video": {
|
||||
"name": "Turn Off at End",
|
||||
"placeholder": "Automatically turn off screen when control stops",
|
||||
"tips": ""
|
||||
},
|
||||
"control-in-stop-charging": {
|
||||
"name": "Stop Charging",
|
||||
"placeholder": "Stop charging when controlling device",
|
||||
"tips": "May not work on some models"
|
||||
}
|
||||
},
|
||||
|
||||
"window": {
|
||||
"name": "Window",
|
||||
"borderless": "Borderless Mode",
|
||||
"full-screen": "Full Screen Mode",
|
||||
"always-top": "Always on Top",
|
||||
"disable-screen-saver": "Disable Screensaver"
|
||||
"borderless": {
|
||||
"name": "Borderless",
|
||||
"placeholder": "Removes window border",
|
||||
"tips": ""
|
||||
},
|
||||
"full-screen": {
|
||||
"name": "Fullscreen",
|
||||
"placeholder": "Fullscreen mode",
|
||||
"tips": ""
|
||||
},
|
||||
"always-top": {
|
||||
"name": "Always on Top",
|
||||
"placeholder": "Window always on top",
|
||||
"tips": ""
|
||||
},
|
||||
"disable-screen-saver": {
|
||||
"name": "Disable Screen Saver",
|
||||
"placeholder": "Disables screen saver",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"record": {
|
||||
"name": "Recording",
|
||||
"format": "Video Recording Format"
|
||||
"format": {
|
||||
"name": "Format",
|
||||
"placeholder": "Default .mp4 format",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"audio": {
|
||||
"name": "Audio",
|
||||
"disable": "Disable Audio"
|
||||
},
|
||||
|
||||
"reset": "Restore Default Values"
|
||||
"disable": {
|
||||
"name": "Disable Audio",
|
||||
"placeholder": "Disables audio",
|
||||
"tips": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"name": "About",
|
||||
"description": "📱 Use the graphical Scrcpy powered by Electron to display and control your Android device.",
|
||||
"update": "Check for Updates",
|
||||
"updating": "Updating",
|
||||
"update-not-available": "Already the latest version",
|
||||
"description": "📱 Display and control your Android device with graphical Scrcpy, powered by Electron",
|
||||
"update": "Check for updates",
|
||||
"update-not-available": "Already up to date",
|
||||
"update-error": {
|
||||
"title": "Update Check Failed",
|
||||
"message": "You may need to use a VPN. Do you want to visit the release page and manually download the update?"
|
||||
"title": "Update check failed",
|
||||
"message": "You may need a VPN. Go to releases page to download manually?"
|
||||
},
|
||||
"update-downloaded": {
|
||||
"title": "New Version Downloaded",
|
||||
"message": "Do you want to restart and apply the update now?",
|
||||
"title": "New version downloaded",
|
||||
"message": "Restart now to update?",
|
||||
"confirm": "Update"
|
||||
},
|
||||
"update-available": {
|
||||
"title": "New Version Available",
|
||||
"title": "New version available",
|
||||
"confirm": "Update"
|
||||
}
|
||||
},
|
||||
"updating": "Updating..."
|
||||
}
|
||||
}
|
||||
|
@ -5,50 +5,79 @@
|
||||
},
|
||||
"devices": {
|
||||
"name": "设备列表",
|
||||
|
||||
"loading": "努力加载中...",
|
||||
|
||||
"empty": "没有检测到设备",
|
||||
|
||||
"wireless": {
|
||||
"name": "无线连接",
|
||||
"connect": "连接设备",
|
||||
"error": {
|
||||
"title": "连接设备失败",
|
||||
"detail": "错误详情",
|
||||
"reasons": [
|
||||
"可能有以下原因",
|
||||
"IP地址或端口号错误",
|
||||
"设备未与当前电脑配对成功",
|
||||
"电脑网络和提供的设备网络IP不在同一个局域网中",
|
||||
"adb 依赖路径错误",
|
||||
"其他未知错误"
|
||||
],
|
||||
"confirm": "无线配对",
|
||||
"cancel": "@:common.cancel"
|
||||
"mode": "无线模式",
|
||||
"connect": {
|
||||
"name": "连接设备",
|
||||
"error": {
|
||||
"title": "连接设备失败",
|
||||
"detail": "错误详情",
|
||||
"reasons": [
|
||||
"可能有以下原因",
|
||||
"IP地址或端口号错误",
|
||||
"设备未与当前电脑配对成功",
|
||||
"电脑网络和提供的设备网络IP不在同一个局域网中",
|
||||
"adb 依赖路径错误",
|
||||
"其他未知错误"
|
||||
],
|
||||
"confirm": "无线配对",
|
||||
"cancel": "@:common.cancel",
|
||||
"no-address": "无线调试地址不能为空"
|
||||
},
|
||||
"success": "连接设备成功"
|
||||
},
|
||||
"success": "连接设备成功"
|
||||
"disconnect": {
|
||||
"start": "断开连接",
|
||||
"progress": "正在断开",
|
||||
"success": "断开连接成功"
|
||||
}
|
||||
},
|
||||
"reset": {
|
||||
"title": "操作失败",
|
||||
"reasons": [
|
||||
"通常情况下,这可能是因为更新 Escrcpy 后,缓存的依赖配置不兼容所导致的,是否重置依赖配置?",
|
||||
"注意:重置后,之前保存的依赖配置将会被清除,因此建议在执行重置操作之前备份您的配置。"
|
||||
],
|
||||
"confirm": "重置依赖配置",
|
||||
"cancel": "@:common.cancel",
|
||||
"success": "操作成功,请重新尝试。"
|
||||
},
|
||||
"refresh": {
|
||||
"name": "刷新设备"
|
||||
},
|
||||
"restart": {
|
||||
"name": "重启服务"
|
||||
},
|
||||
"log": {
|
||||
"name": "运行日志"
|
||||
},
|
||||
|
||||
"refresh": "刷新设备",
|
||||
"restart": "重启服务",
|
||||
|
||||
"device": {
|
||||
"id": "设备 ID",
|
||||
"name": "设备名称",
|
||||
"remark": "备注"
|
||||
"remark": "备注",
|
||||
"permission": {
|
||||
"error": "设备可能未授权成功,请重新插拔设备并点击允许USB调试"
|
||||
}
|
||||
},
|
||||
"mirror": {
|
||||
"start": "开始镜像",
|
||||
"progress": "正在镜像"
|
||||
},
|
||||
"record": {
|
||||
"start": "开始录制",
|
||||
"progress": "正在录制",
|
||||
"success": {
|
||||
"title": "录制成功",
|
||||
"message": "是否前往录制位置进行查看?"
|
||||
}
|
||||
},
|
||||
|
||||
"operates": {
|
||||
"name": "操作",
|
||||
"more": "设备交互",
|
||||
"mirror": "开始镜像",
|
||||
"mirroring": "正在镜像",
|
||||
"record": "开始录制",
|
||||
"recording": "正在录制",
|
||||
"wireless": "无线模式",
|
||||
"disconnect": "断开连接",
|
||||
"disconnecting": "正在断开",
|
||||
"install": "安装应用",
|
||||
"capture": "截取屏幕",
|
||||
"reboot": "重启设备",
|
||||
@ -59,87 +88,195 @@
|
||||
"switch": "切换键"
|
||||
}
|
||||
},
|
||||
|
||||
"preferences": {
|
||||
"name": "偏好设置",
|
||||
"global": "全局",
|
||||
|
||||
"config": {
|
||||
"import": "导入配置",
|
||||
"export": "导出配置",
|
||||
"edit": "编辑配置",
|
||||
"reset": "重置配置"
|
||||
"reset": "恢复默认值",
|
||||
"scope": {
|
||||
"global": "全局",
|
||||
"placeholder": "偏好设置的作用域范围",
|
||||
"no-data": "暂无数据",
|
||||
"details": [
|
||||
"对全局或者单个设备设置不同的偏好配置",
|
||||
"全局:将对所有设备生效。",
|
||||
"单个设备:继承于全局配置,并对单个设备进行独立设置,仅对此设备生效。"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"import": {
|
||||
"name": "导入配置",
|
||||
"placeholder": "请选择要导入的配置文件",
|
||||
"success": "导入成功"
|
||||
},
|
||||
"export": {
|
||||
"name": "导出配置",
|
||||
"message": "导出配置",
|
||||
"placeholder": "请选择要导出的位置",
|
||||
"success": "导出成功"
|
||||
},
|
||||
"edit": {
|
||||
"name": "编辑配置"
|
||||
},
|
||||
"reset": {
|
||||
"name": "重置配置"
|
||||
},
|
||||
"save": {
|
||||
"name": "保存配置",
|
||||
"placeholder": "保存配置成功,将在下一次控制设备时生效"
|
||||
}
|
||||
},
|
||||
|
||||
"custom": {
|
||||
"name": "自定义",
|
||||
"file-path": {
|
||||
"file": {
|
||||
"name": "文件存储路径",
|
||||
"placeholder": "默认情况下放在用户桌面上",
|
||||
"tips": "截图和录制的音视频存放在这里"
|
||||
},
|
||||
"adb-path": {
|
||||
"adb": {
|
||||
"name": "adb 路径",
|
||||
"placeholder": "请设置 adb 路径",
|
||||
"tips": "用于连接设备的 adb 地址。注意:此选项不受单个设备配置的影响"
|
||||
},
|
||||
"scrcpy-path": {
|
||||
"scrcpy": {
|
||||
"name": "scrcpy 路径",
|
||||
"placeholder": "请设置 scrcpy 路径",
|
||||
"tips": "用于连接设备的 scrcpy 地址。注意:此选项不受单个设备配置的影响"
|
||||
}
|
||||
},
|
||||
|
||||
"video": {
|
||||
"name": "视频控制",
|
||||
"resolution": "分辨率",
|
||||
"bit": "比特率",
|
||||
"refresh-rate": "刷新率",
|
||||
"decoder": "视频解码器",
|
||||
"encoder": "视频编码器",
|
||||
"screen-rotation": "屏幕旋转",
|
||||
"screen-cropping": "屏幕裁剪",
|
||||
"multi-display": "多显示器",
|
||||
"video-buffering": "视频缓冲",
|
||||
"audio-buffering": "音频缓冲",
|
||||
"receiver-buffering": "接收器缓冲(v412)",
|
||||
"disable": "禁用视频"
|
||||
"resolution": {
|
||||
"name": "分辨率",
|
||||
"placeholder": "默认值为设备分辨率,如 1920",
|
||||
"tips": ""
|
||||
},
|
||||
"bit": {
|
||||
"name": "比特率",
|
||||
"placeholder": "默认值为 4M,等同于 4000000",
|
||||
"tips": ""
|
||||
},
|
||||
"refresh-rate": {
|
||||
"name": "刷新率",
|
||||
"placeholder": "默认值为 60",
|
||||
"tips": ""
|
||||
},
|
||||
"decoder": {
|
||||
"name": "视频解码器",
|
||||
"placeholder": "默认值为 h264",
|
||||
"tips": ""
|
||||
},
|
||||
"encoder": {
|
||||
"name": "视频编码器",
|
||||
"placeholder": "默认值为设备默认编码器",
|
||||
"tips": ""
|
||||
},
|
||||
"screen-rotation": {
|
||||
"name": "屏幕旋转",
|
||||
"placeholder": "默认值为设备屏幕旋转角度",
|
||||
"tips": ""
|
||||
},
|
||||
"screen-cropping": {
|
||||
"name": "屏幕裁剪",
|
||||
"placeholder": "默认不裁剪,格式为 1224:1440:0:0",
|
||||
"tips": ""
|
||||
},
|
||||
"multi-display": {
|
||||
"name": "多显示器",
|
||||
"placeholder": "默认值为 0(主屏幕)",
|
||||
"tips": ""
|
||||
},
|
||||
"video-buffering": {
|
||||
"name": "视频缓冲",
|
||||
"placeholder": "默认值为 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"audio-buffering": {
|
||||
"name": "音频缓冲",
|
||||
"placeholder": "默认值为 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"receiver-buffering": {
|
||||
"name": "接收器缓冲(v412)",
|
||||
"placeholder": "默认值为 0ms",
|
||||
"tips": ""
|
||||
},
|
||||
"disable": {
|
||||
"name": "禁用视频",
|
||||
"placeholder": "开启后将禁用视频",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"device": {
|
||||
"name": "设备控制",
|
||||
"show-touch": "展示触摸点",
|
||||
"stay-awake": "保持清醒",
|
||||
"control-in-close-screen": "控制时关闭屏幕",
|
||||
"control-end-video": "控制结束关闭屏幕",
|
||||
"control-in-stop-charging": "控制时停止充电"
|
||||
"show-touch": {
|
||||
"name": "展示触摸点",
|
||||
"placeholder": "开启后将打开开发者选项中的显示点按触摸反馈",
|
||||
"tips": "仅在物理设备上展示"
|
||||
},
|
||||
"stay-awake": {
|
||||
"name": "保持清醒",
|
||||
"placeholder": "开启以防止设备进入睡眠状态",
|
||||
"tips": "仅有线方式连接时有效"
|
||||
},
|
||||
"control-in-close-screen": {
|
||||
"name": "控制时关闭屏幕",
|
||||
"placeholder": "开启后控制设备时将自动关闭设备屏幕",
|
||||
"tips": ""
|
||||
},
|
||||
"control-end-video": {
|
||||
"name": "控制结束关闭屏幕",
|
||||
"placeholder": "开启后停止控制设备将自动关闭设备屏幕",
|
||||
"tips": ""
|
||||
},
|
||||
"control-in-stop-charging": {
|
||||
"name": "控制时停止充电",
|
||||
"placeholder": "开启后控制设备时将停止充电",
|
||||
"tips": "某些机型上似乎不起作用"
|
||||
}
|
||||
},
|
||||
|
||||
"window": {
|
||||
"name": "窗口控制",
|
||||
"borderless": "无边框模式",
|
||||
"full-screen": "全屏模式",
|
||||
"always-top": "始终位于顶部",
|
||||
"disable-screen-saver": "禁用屏幕保护程序"
|
||||
"borderless": {
|
||||
"name": "无边框模式",
|
||||
"placeholder": "开启后控制窗口将变为无边框模式",
|
||||
"tips": ""
|
||||
},
|
||||
"full-screen": {
|
||||
"name": "全屏模式",
|
||||
"placeholder": "开启后控制窗口将全屏显示模式",
|
||||
"tips": ""
|
||||
},
|
||||
"always-top": {
|
||||
"name": "始终位于顶部",
|
||||
"placeholder": "开启后控制窗口将始终位于顶部",
|
||||
"tips": ""
|
||||
},
|
||||
"disable-screen-saver": {
|
||||
"name": "禁用屏幕保护程序",
|
||||
"placeholder": "开启后将禁用计算机屏幕保护程序",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"record": {
|
||||
"name": "音视频录制",
|
||||
"format": "录制视频格式"
|
||||
"format": {
|
||||
"name": "录制视频格式",
|
||||
"placeholder": "默认为 *.mp4 格式",
|
||||
"tips": ""
|
||||
}
|
||||
},
|
||||
|
||||
"audio": {
|
||||
"name": "音频控制",
|
||||
"disable": "禁用音频"
|
||||
},
|
||||
|
||||
"reset": "恢复默认值"
|
||||
"disable": {
|
||||
"name": "禁用音频",
|
||||
"placeholder": "开启后将禁用音频功能",
|
||||
"tips": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"about": {
|
||||
"name": "关于",
|
||||
"description": "📱 使用图形化的 Scrcpy 显示和控制您的 Android 设备,由 Electron 驱动",
|
||||
"update": "版本检测更新",
|
||||
"update": "检查并更新",
|
||||
"update-not-available": "已经是最新版本",
|
||||
"update-error": {
|
||||
"title": "检查更新失败",
|
||||
@ -153,6 +290,7 @@
|
||||
"update-available": {
|
||||
"title": "发现新版本",
|
||||
"confirm": "更新"
|
||||
}
|
||||
},
|
||||
"updating": "正在更新中"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import '@/utils/console.js'
|
||||
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
|
||||
@ -29,9 +31,13 @@ app.config.globalProperties.$scrcpy = window.scrcpy
|
||||
app.config.globalProperties.$path = window.nodePath
|
||||
app.config.globalProperties.$appStore = window.appStore
|
||||
|
||||
app.config.globalProperties.$appLog = window.appLog
|
||||
|
||||
app.config.globalProperties.$replaceIP = replaceIP
|
||||
|
||||
app.mount('#app').$nextTick(() => {
|
||||
// Remove Preload scripts loading
|
||||
postMessage({ payload: 'removeLoading' }, '*')
|
||||
})
|
||||
|
||||
console.log('electron.configs', window.electron.configs)
|
||||
|
@ -36,7 +36,7 @@ function getDefaultConfig(type) {
|
||||
model.push(...handler())
|
||||
}
|
||||
else {
|
||||
// console.log('scrcpyModel', scrcpyModel)
|
||||
// console.raw('scrcpyModel', scrcpyModel)
|
||||
const values = Object.values(scrcpyModel)
|
||||
model.push(...values.flatMap(handler => handler()))
|
||||
}
|
||||
@ -55,7 +55,7 @@ export const useScrcpyStore = defineStore({
|
||||
state() {
|
||||
return {
|
||||
scope: $appStore.get('scrcpy.scope') || 'global',
|
||||
model: scrcpyModel,
|
||||
model: { ...scrcpyModel },
|
||||
defaultConfig: getDefaultConfig(),
|
||||
config: {},
|
||||
excludeKeys: ['--record-format', 'savePath', 'adbPath', 'scrcpyPath'],
|
||||
@ -166,8 +166,20 @@ export const useScrcpyStore = defineStore({
|
||||
return value
|
||||
},
|
||||
getModel(key, params) {
|
||||
const handler = scrcpyModel[key]
|
||||
return handler(params)
|
||||
const handler = this.model[key]
|
||||
const value = handler(params)
|
||||
// console.log('setModel.value', value)
|
||||
|
||||
return value
|
||||
},
|
||||
setModel(key, params) {
|
||||
const handler = this.model[key]
|
||||
const value = handler(params)
|
||||
// console.log('setModel.value', value)
|
||||
|
||||
this.model[key] = () => value
|
||||
|
||||
return this.model
|
||||
},
|
||||
},
|
||||
})
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { t } from '@/locales/index.js'
|
||||
|
||||
export default () => {
|
||||
// "[server] INFO: List of audio encoders:"
|
||||
// "--audio-codec=opus --audio-encoder='c2.android.opus.encoder'"
|
||||
@ -5,11 +7,11 @@ export default () => {
|
||||
// "--audio-codec=aac --audio-encoder='OMX.google.aac.encoder'"
|
||||
return [
|
||||
{
|
||||
label: '禁用音频',
|
||||
label: t('preferences.audio.disable.name'),
|
||||
field: '--no-audio',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后将禁用音频功能',
|
||||
placeholder: t('preferences.audio.disable.placeholder'),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -5,36 +5,34 @@ export default () => {
|
||||
|
||||
return [
|
||||
{
|
||||
label: t('preferences.custom.file-path.name'),
|
||||
label: t('preferences.custom.file.name'),
|
||||
type: 'input.path',
|
||||
field: 'savePath',
|
||||
value: desktopPath,
|
||||
placeholder: t('preferences.custom.file-path.placeholder'),
|
||||
tips: t('preferences.custom.file-path.tips'),
|
||||
placeholder: t('preferences.custom.file.placeholder'),
|
||||
tips: t('preferences.custom.file.tips'),
|
||||
properties: ['openDirectory'],
|
||||
},
|
||||
{
|
||||
label: t('preferences.custom.adb-path.name'),
|
||||
label: t('preferences.custom.adb.name'),
|
||||
field: 'adbPath',
|
||||
type: 'input.path',
|
||||
value: adbPath,
|
||||
placeholder: t('preferences.custom.adb-path.placeholder'),
|
||||
tips: t('preferences.custom.adb-path.tips'),
|
||||
placeholder: t('preferences.custom.adb.placeholder'),
|
||||
tips: t('preferences.custom.adb.tips'),
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{ name: t('preferences.custom.adb-path.name'), extensions: ['*'] },
|
||||
],
|
||||
filters: [{ name: t('preferences.custom.adb.name'), extensions: ['*'] }],
|
||||
},
|
||||
{
|
||||
label: t('preferences.custom.scrcpy-path.name'),
|
||||
label: t('preferences.custom.scrcpy.name'),
|
||||
field: 'scrcpyPath',
|
||||
type: 'input.path',
|
||||
value: scrcpyPath,
|
||||
placeholder: t('preferences.custom.scrcpy-path.placeholder'),
|
||||
tips: t('preferences.custom.scrcpy-path.tips'),
|
||||
placeholder: t('preferences.custom.scrcpy.placeholder'),
|
||||
tips: t('preferences.custom.scrcpy.tips'),
|
||||
properties: ['openFile'],
|
||||
filters: [
|
||||
{ name: t('preferences.custom.scrcpy-path.name'), extensions: ['*'] },
|
||||
{ name: t('preferences.custom.scrcpy.name'), extensions: ['*'] },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
@ -1,42 +1,44 @@
|
||||
import { t } from '@/locales/index.js'
|
||||
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '展示触摸点',
|
||||
label: t('preferences.device.show-touch.name'),
|
||||
type: 'switch',
|
||||
field: '--show-touches',
|
||||
value: false,
|
||||
placeholder: '开启后将打开开发者选项中的显示点按触摸反馈',
|
||||
tips: '仅在物理设备上展示',
|
||||
placeholder: t('preferences.device.show-touch.placeholder'),
|
||||
tips: t('preferences.device.show-touch.tips'),
|
||||
},
|
||||
{
|
||||
label: '保持清醒',
|
||||
label: t('preferences.device.stay-awake.name'),
|
||||
type: 'switch',
|
||||
field: '--stay-awake',
|
||||
value: false,
|
||||
placeholder: '开启以防止设备进入睡眠状态',
|
||||
tips: '仅有线方式连接时有效',
|
||||
placeholder: t('preferences.device.stay-awake.placeholder'),
|
||||
tips: t('preferences.device.stay-awake.tips'),
|
||||
},
|
||||
{
|
||||
label: '控制时关闭屏幕',
|
||||
label: t('preferences.device.control-in-close-screen.name'),
|
||||
type: 'switch',
|
||||
field: '--turn-screen-off',
|
||||
value: false,
|
||||
placeholder: '开启后控制设备时将自动关闭设备屏幕',
|
||||
placeholder: t('preferences.device.control-in-close-screen.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '控制结束关闭屏幕',
|
||||
label: t('preferences.device.control-end-video.name'),
|
||||
type: 'switch',
|
||||
field: '--power-off-on-close',
|
||||
value: false,
|
||||
placeholder: '开启后停止控制设备将自动关闭设备屏幕',
|
||||
placeholder: t('preferences.device.control-end-video.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '控制时停止充电',
|
||||
label: t('preferences.device.control-in-stop-charging.name'),
|
||||
type: 'switch',
|
||||
field: '--no-power-on',
|
||||
value: false,
|
||||
placeholder: '开启后控制设备时将停止充电',
|
||||
tips: '某些机型上似乎不起作用',
|
||||
placeholder: t('preferences.device.control-in-stop-charging.placeholder'),
|
||||
tips: t('preferences.device.control-in-stop-charging.tips'),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { t } from '@/locales/index.js'
|
||||
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '录制视频格式',
|
||||
label: t('preferences.record.format.name'),
|
||||
type: 'select',
|
||||
field: '--record-format',
|
||||
value: 'mp4',
|
||||
placeholder: '默认值为 mp4',
|
||||
placeholder: t('preferences.record.format.placeholder'),
|
||||
options: [
|
||||
{
|
||||
label: 'mp4',
|
||||
|
@ -1,32 +1,45 @@
|
||||
export default () => {
|
||||
import { t } from '@/locales/index.js'
|
||||
|
||||
const getDisplayOptions = (display = []) =>
|
||||
display?.map(value => ({ label: value, value })) || []
|
||||
|
||||
export default ({ display } = {}) => {
|
||||
const displayOptions = display?.length
|
||||
? getDisplayOptions(display)
|
||||
: [
|
||||
{ label: '0', value: '0' },
|
||||
{ label: '1', value: '1' },
|
||||
{ label: '2', value: '2' },
|
||||
]
|
||||
|
||||
return [
|
||||
{
|
||||
label: '分辨率',
|
||||
label: t('preferences.video.resolution.name'),
|
||||
type: 'input.number',
|
||||
field: '--max-size',
|
||||
value: '',
|
||||
placeholder: '默认值为设备分辨率,如 1920',
|
||||
placeholder: t('preferences.video.resolution.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '比特率',
|
||||
label: t('preferences.video.bit.name'),
|
||||
type: 'input',
|
||||
field: '--video-bit-rate',
|
||||
value: '',
|
||||
placeholder: '默认值为 4M,等同于 4000000',
|
||||
placeholder: t('preferences.video.bit.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '刷新率',
|
||||
label: t('preferences.video.refresh-rate.name'),
|
||||
type: 'input.number',
|
||||
field: '--max-fps',
|
||||
value: '',
|
||||
placeholder: '默认值为 60',
|
||||
placeholder: t('preferences.video.refresh-rate.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '视频解码器',
|
||||
label: t('preferences.video.decoder.name'),
|
||||
type: 'select',
|
||||
field: '--video-codec',
|
||||
value: '',
|
||||
placeholder: '默认值为 h264',
|
||||
placeholder: t('preferences.video.decoder.placeholder'),
|
||||
options: [
|
||||
{
|
||||
label: 'h264',
|
||||
@ -43,11 +56,11 @@ export default () => {
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '视频编码器',
|
||||
label: t('preferences.video.encoder.name'),
|
||||
type: 'select',
|
||||
field: '--video-encoder',
|
||||
value: '',
|
||||
placeholder: '默认值为设备默认编码器',
|
||||
placeholder: t('preferences.video.encoder.placeholder'),
|
||||
// "[server] INFO: List of video encoders:"
|
||||
// "--video-codec=h264 --video-encoder='OMX.qcom.video.encoder.avc'"
|
||||
// "--video-codec=h264 --video-encoder='c2.android.avc.encoder'"
|
||||
@ -56,33 +69,33 @@ export default () => {
|
||||
// "--video-codec=h265 --video-encoder='c2.android.hevc.encoder'"
|
||||
options: [
|
||||
{
|
||||
label: 'Qualcomm AVC(H.264) 视频编码器',
|
||||
label: 'Android HEVC(H.265) ',
|
||||
value: 'OMX.qcom.video.encoder.avc',
|
||||
},
|
||||
{
|
||||
label: 'Android AVC(H.264) 视频编码器',
|
||||
label: 'Qualcomm HEVC(H.265) ',
|
||||
value: 'c2.android.avc.encoder',
|
||||
},
|
||||
{
|
||||
label: 'Google H.264(AVC) 视频编码器',
|
||||
label: 'Google H.264(AVC)',
|
||||
value: 'OMX.google.h264.encoder',
|
||||
},
|
||||
{
|
||||
label: 'Qualcomm HEVC(H.265) 视频编码器',
|
||||
label: 'Android AVC(H.264) ',
|
||||
value: 'OMX.qcom.video.encoder.hevc',
|
||||
},
|
||||
{
|
||||
label: 'Android HEVC(H.265) 视频编码器',
|
||||
label: 'Qualcomm AVC(H.264)',
|
||||
value: 'c2.android.hevc.encoder',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '屏幕旋转',
|
||||
label: t('preferences.video.screen-rotation.name'),
|
||||
type: 'select',
|
||||
field: '--rotation',
|
||||
value: '',
|
||||
placeholder: '默认值为设备屏幕旋转角度',
|
||||
placeholder: t('preferences.video.screen-rotation.placeholder'),
|
||||
options: [
|
||||
{ label: '0°', value: '0' },
|
||||
{ label: '-90°', value: '1' },
|
||||
@ -91,51 +104,51 @@ export default () => {
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '屏幕裁剪',
|
||||
label: t('preferences.video.screen-cropping.name'),
|
||||
type: 'input',
|
||||
field: '--crop',
|
||||
value: '',
|
||||
placeholder: '默认不裁剪,格式为 1224:1440:0:0',
|
||||
placeholder: t('preferences.video.screen-cropping.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '多显示器',
|
||||
label: t('preferences.video.multi-display.name'),
|
||||
type: 'select',
|
||||
field: '--display',
|
||||
value: '',
|
||||
placeholder: '默认值为 0(主屏幕)',
|
||||
options: [
|
||||
{ label: '0', value: '0' },
|
||||
{ label: '1', value: '1' },
|
||||
{ label: '2', value: '2' },
|
||||
],
|
||||
placeholder: t('preferences.video.multi-display.placeholder'),
|
||||
options: displayOptions,
|
||||
props: {
|
||||
filterable: true,
|
||||
allowCreate: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '视频缓冲',
|
||||
label: t('preferences.video.video-buffering.name'),
|
||||
type: 'input.number',
|
||||
field: '--display-buffer',
|
||||
value: '',
|
||||
placeholder: '单位为 ms,默认值为 0ms',
|
||||
placeholder: t('preferences.video.video-buffering.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '音频缓冲',
|
||||
label: t('preferences.video.audio-buffering.name'),
|
||||
type: 'input.number',
|
||||
field: '--audio-buffer',
|
||||
value: '',
|
||||
placeholder: '单位为 ms,默认值为 0ms',
|
||||
placeholder: t('preferences.video.video-buffering.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '接收器(v4l2)缓冲',
|
||||
label: t('preferences.video.receiver-buffering.name'),
|
||||
type: 'input.number',
|
||||
field: '--v4l2-buffer',
|
||||
value: '',
|
||||
placeholder: '单位为 ms,默认值为 0ms',
|
||||
placeholder: t('preferences.video.video-buffering.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '禁用视频',
|
||||
label: t('preferences.video.disable.name'),
|
||||
type: 'switch',
|
||||
field: '--no-video',
|
||||
value: false,
|
||||
placeholder: '开启后将禁用视频',
|
||||
placeholder: t('preferences.video.disable.placeholder'),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
@ -1,32 +1,34 @@
|
||||
import { t } from '@/locales/index.js'
|
||||
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '无边框模式',
|
||||
label: t('preferences.window.borderless.name'),
|
||||
field: '--window-borderless',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后控制窗口将变为无边框模式',
|
||||
placeholder: t('preferences.window.borderless.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '全屏模式',
|
||||
label: t('preferences.window.full-screen.name'),
|
||||
field: '--fullscreen',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后控制窗口将全屏显示模式',
|
||||
placeholder: t('preferences.window.full-screen.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '始终位于顶部',
|
||||
label: t('preferences.window.always-top.name'),
|
||||
field: '--always-on-top',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后控制窗口将始终位于顶部',
|
||||
placeholder: t('preferences.window.always-top.placeholder'),
|
||||
},
|
||||
{
|
||||
label: '禁用屏幕保护程序',
|
||||
label: t('preferences.window.disable-screen-saver.name'),
|
||||
field: '--disable-screensaver',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后将禁用计算机屏幕保护程序',
|
||||
placeholder: t('preferences.window.disable-screen-saver.placeholder'),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
6
src/utils/console.js
Normal file
6
src/utils/console.js
Normal file
@ -0,0 +1,6 @@
|
||||
import { createProxy } from './index.js'
|
||||
|
||||
Object.assign(console, {
|
||||
...createProxy(window.appLog.functions, window.appLog.levels),
|
||||
raw: console.log,
|
||||
})
|
@ -1,3 +1,5 @@
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
/**
|
||||
* @desc 使用async await 进项进行延时操作
|
||||
* @param {*} time
|
||||
@ -18,3 +20,20 @@ export function isIPWithPort(ip) {
|
||||
export function replaceIP(value, to = '_') {
|
||||
return value.replaceAll('.', to).replaceAll(':', to)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个代理对象,将目标对象的指定方法转发并执行。
|
||||
*
|
||||
* @param {object} targetObject - 目标对象,包含要代理的方法。
|
||||
* @param {string[]} methodNames - 要代理的方法名称数组。
|
||||
* @returns {object} - 代理对象,包含转发的方法。
|
||||
*/
|
||||
export function createProxy(targetObject, methodNames) {
|
||||
return methodNames.reduce((proxyObj, methodName) => {
|
||||
proxyObj[methodName] = (...args) => {
|
||||
return targetObject[methodName](...cloneDeep(args))
|
||||
}
|
||||
|
||||
return proxyObj
|
||||
}, {})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user