mirror of
https://gitee.com/viarotel-org/escrcpy.git
synced 2024-12-02 11:17:36 +08:00
feat: 🚀 增加了常用的 Scrcpy 高级配置
This commit is contained in:
parent
0695aa3377
commit
ac52df2add
@ -2,5 +2,5 @@ out
|
||||
dist
|
||||
pnpm-lock.yaml
|
||||
LICENSE.md
|
||||
tsconfig.json
|
||||
tsconfig.*.json
|
||||
jsconfig.json
|
||||
jsconfig.*.json
|
||||
|
@ -8,7 +8,7 @@
|
||||
:name="item.prop"
|
||||
lazy
|
||||
>
|
||||
<component :is="item.prop" />
|
||||
<component :is="item.prop" ref="component" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
@ -39,11 +39,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {},
|
||||
methods: {
|
||||
getDevices() {
|
||||
window.adbkit.createClient()
|
||||
},
|
||||
},
|
||||
methods: {},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
15
src/renderer/src/components/Advanced/configs/audio/index.js
Normal file
15
src/renderer/src/components/Advanced/configs/audio/index.js
Normal file
@ -0,0 +1,15 @@
|
||||
export default () => {
|
||||
// "[server] INFO: List of audio encoders:"
|
||||
// "--audio-codec=opus --audio-encoder='c2.android.opus.encoder'"
|
||||
// "--audio-codec=aac --audio-encoder='c2.android.aac.encoder'"
|
||||
// "--audio-codec=aac --audio-encoder='OMX.google.aac.encoder'"
|
||||
return [
|
||||
{
|
||||
label: '禁用音频',
|
||||
field: '--no-audio',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启后将禁用音频功能',
|
||||
},
|
||||
]
|
||||
}
|
18
src/renderer/src/components/Advanced/configs/device/index.js
Normal file
18
src/renderer/src/components/Advanced/configs/device/index.js
Normal file
@ -0,0 +1,18 @@
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '保持清醒',
|
||||
type: 'switch',
|
||||
field: '--stay-awake',
|
||||
value: false,
|
||||
placeholder: '开启以防止设备进入睡眠状态(仅有线方式连接时有效)',
|
||||
},
|
||||
{
|
||||
label: '关闭屏幕',
|
||||
type: 'switch',
|
||||
field: '--turn-screen-off',
|
||||
value: false,
|
||||
placeholder: '开启后连接镜像时将自动关闭设备屏幕',
|
||||
},
|
||||
]
|
||||
}
|
4
src/renderer/src/components/Advanced/configs/index.js
Normal file
4
src/renderer/src/components/Advanced/configs/index.js
Normal file
@ -0,0 +1,4 @@
|
||||
export { default as video } from './video/index.js'
|
||||
export { default as device } from './device/index.js'
|
||||
export { default as window } from './window/index.js'
|
||||
export { default as audio } from './audio/index.js'
|
94
src/renderer/src/components/Advanced/configs/video/index.js
Normal file
94
src/renderer/src/components/Advanced/configs/video/index.js
Normal file
@ -0,0 +1,94 @@
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '分辨率',
|
||||
type: 'input.number',
|
||||
field: '--max-size',
|
||||
value: '',
|
||||
placeholder: '默认值为设备分辨率,如 1920',
|
||||
},
|
||||
{
|
||||
label: '比特率',
|
||||
type: 'input',
|
||||
field: '--video-bit-rate',
|
||||
value: '',
|
||||
placeholder: '默认值为 4M,等同于 4000000',
|
||||
},
|
||||
{
|
||||
label: '刷新率',
|
||||
type: 'input.number',
|
||||
field: '--max-fps',
|
||||
value: '',
|
||||
placeholder: '默认值为 60',
|
||||
},
|
||||
{
|
||||
label: '屏幕旋转',
|
||||
type: 'select',
|
||||
field: '--rotation=0',
|
||||
value: '',
|
||||
placeholder: '默认值为设备屏幕旋转角度',
|
||||
options: [
|
||||
{ label: '0°', value: '0' },
|
||||
{ label: '-90°', value: '1' },
|
||||
{ label: '180°', value: '2' },
|
||||
{ label: '90°', value: '3' },
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '解码器',
|
||||
type: 'select',
|
||||
field: '--video-codec',
|
||||
value: '',
|
||||
placeholder: '解码器默认值为 h264',
|
||||
options: [
|
||||
{
|
||||
label: 'h264',
|
||||
value: 'h264',
|
||||
},
|
||||
{
|
||||
label: 'h265',
|
||||
value: 'h265',
|
||||
},
|
||||
{
|
||||
label: 'av1',
|
||||
value: 'av1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '编码器',
|
||||
type: 'select',
|
||||
field: '--video-encoder',
|
||||
value: '',
|
||||
placeholder: '编码器默认值为 h264',
|
||||
// "[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'"
|
||||
// "--video-codec=h264 --video-encoder='OMX.google.h264.encoder'"
|
||||
// "--video-codec=h265 --video-encoder='OMX.qcom.video.encoder.hevc'"
|
||||
// "--video-codec=h265 --video-encoder='c2.android.hevc.encoder'"
|
||||
options: [
|
||||
{
|
||||
label: 'OMX.qcom.video.encoder.avc',
|
||||
value: 'OMX.qcom.video.encoder.avc',
|
||||
},
|
||||
{
|
||||
label: 'c2.android.avc.encoder',
|
||||
value: 'c2.android.avc.encoder',
|
||||
},
|
||||
{
|
||||
label: 'OMX.google.h264.encoder',
|
||||
value: 'OMX.google.h264.encoder',
|
||||
},
|
||||
{
|
||||
label: 'OMX.qcom.video.encoder.hevc',
|
||||
value: 'OMX.qcom.video.encoder.hevc',
|
||||
},
|
||||
{
|
||||
label: 'c2.android.hevc.encoder',
|
||||
value: 'c2.android.hevc.encoder',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
}
|
18
src/renderer/src/components/Advanced/configs/window/index.js
Normal file
18
src/renderer/src/components/Advanced/configs/window/index.js
Normal file
@ -0,0 +1,18 @@
|
||||
export default () => {
|
||||
return [
|
||||
{
|
||||
label: '无边框模式',
|
||||
field: '--window-borderless',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启无边框模式',
|
||||
},
|
||||
{
|
||||
label: '全屏模式',
|
||||
field: '--fullscreen',
|
||||
type: 'switch',
|
||||
value: false,
|
||||
placeholder: '开启全屏模式',
|
||||
},
|
||||
]
|
||||
}
|
@ -1,11 +1,148 @@
|
||||
<template>
|
||||
<div class="grid gap-6 pr-2">
|
||||
<el-card v-for="(item, index) of scrcpyModel" :key="index" shadow="hover" class="">
|
||||
<template #header>
|
||||
<div class="flex items-center">
|
||||
<div class="flex-1 w-0 truncate pl-2 text-base">
|
||||
{{ item.label }}
|
||||
</div>
|
||||
<div class="flex-none pl-4">
|
||||
<el-button type="primary" text @click="handleReset(item.type)">
|
||||
恢复默认值
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="">
|
||||
[WIP]
|
||||
<el-form ref="elForm" :model="scrcpyForm" label-width="120px" class="pr-8 pt-4">
|
||||
<el-row :gutter="20">
|
||||
<el-col
|
||||
v-for="(item_1, index_1) of getScrcpyConfig(item.type)"
|
||||
:key="index_1"
|
||||
:span="12"
|
||||
:offset="0"
|
||||
>
|
||||
<el-form-item :label="item_1.label" :prop="item_1.field">
|
||||
<el-input
|
||||
v-if="item_1.type === 'input'"
|
||||
v-bind="item_1.props || {}"
|
||||
v-model="scrcpyForm[item_1.field]"
|
||||
class="!w-full"
|
||||
:placeholder="item_1.placeholder"
|
||||
></el-input>
|
||||
<el-input
|
||||
v-if="item_1.type === 'input.number'"
|
||||
v-bind="item_1.props || {}"
|
||||
v-model.number="scrcpyForm[item_1.field]"
|
||||
class="!w-full"
|
||||
:placeholder="item_1.placeholder"
|
||||
></el-input>
|
||||
<el-switch
|
||||
v-if="item_1.type === 'switch'"
|
||||
v-bind="item_1.props || {}"
|
||||
v-model="scrcpyForm[item_1.field]"
|
||||
class="!w-full"
|
||||
:placeholder="item_1.placeholder"
|
||||
></el-switch>
|
||||
<el-select
|
||||
v-if="item_1.type === 'select'"
|
||||
v-bind="item_1.props || {}"
|
||||
v-model="scrcpyForm[item_1.field]"
|
||||
:placeholder="item_1.placeholder"
|
||||
class="!w-full"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item_2, index_2) in item_1.options"
|
||||
:key="index_2"
|
||||
:label="item_2.label"
|
||||
:value="item_2.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
import storage from '@renderer/utils/storages'
|
||||
import * as scrcpyConfigs from './configs/index.js'
|
||||
|
||||
export default {
|
||||
emits: ['change'],
|
||||
data() {
|
||||
const scrcpyCache = storage.get('scrcpyCache') || {}
|
||||
// console.log('scrcpyCache', scrcpyCache)
|
||||
|
||||
return {
|
||||
scrcpyModel: [
|
||||
{
|
||||
label: '显示配置',
|
||||
type: 'video',
|
||||
},
|
||||
{
|
||||
label: '设备控制',
|
||||
type: 'device',
|
||||
},
|
||||
{
|
||||
label: '音频控制',
|
||||
type: 'audio',
|
||||
},
|
||||
{
|
||||
label: '窗口控制',
|
||||
type: 'window',
|
||||
},
|
||||
],
|
||||
scrcpyForm: { ...this.getDefaultValues(), ...scrcpyCache },
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scrcpyForm: {
|
||||
handler() {
|
||||
storage.set('scrcpyCache', this.scrcpyForm)
|
||||
this.$message.success('保存配置成功,将在下一次控制设备时生效')
|
||||
},
|
||||
deep: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getScrcpyConfig(type) {
|
||||
const value = scrcpyConfigs[type]()
|
||||
return value
|
||||
},
|
||||
getDefaultValues(type) {
|
||||
const model = []
|
||||
if (type) {
|
||||
model.push(...this.getScrcpyConfig(type))
|
||||
}
|
||||
else {
|
||||
// console.log('scrcpyConfigs', scrcpyConfigs)
|
||||
const values = Object.values(scrcpyConfigs)
|
||||
model.push(...values.flatMap(handler => handler()))
|
||||
}
|
||||
|
||||
const value = model.reduce((obj, item) => {
|
||||
const { field, value } = item
|
||||
obj[field] = value
|
||||
return obj
|
||||
}, {})
|
||||
|
||||
return value
|
||||
},
|
||||
handleReset(type) {
|
||||
this.scrcpyForm = { ...this.scrcpyForm, ...this.getDefaultValues(type) }
|
||||
storage.set('scrcpyCache', this.scrcpyForm)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
<style scoped lang="postcss">
|
||||
:deep(.el-card) {
|
||||
--el-card-padding: 8px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,19 +1,26 @@
|
||||
<template>
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex items-center flex-none space-x-2">
|
||||
<el-input v-model="formData.host" placeholder="192.168.0.1" class="w-72">
|
||||
<el-input v-model="formData.host" placeholder="192.168.0.1" class="w-86" clearable>
|
||||
<template #prepend>
|
||||
无线连接设备
|
||||
无线连接
|
||||
</template>
|
||||
</el-input>
|
||||
<div class="text-gray-500 text-sm">
|
||||
:
|
||||
</div>
|
||||
<el-input v-model.number="formData.port" type="number" placeholder="5555" class="w-24">
|
||||
<el-input
|
||||
v-model.number="formData.port"
|
||||
type="number"
|
||||
placeholder="5555"
|
||||
:min="0"
|
||||
clearable
|
||||
class="w-32"
|
||||
>
|
||||
</el-input>
|
||||
|
||||
<el-button type="primary" :loading="connectLoading" @click="handleConnect">
|
||||
开始连接
|
||||
连接设备
|
||||
</el-button>
|
||||
<el-button type="primary" :loading="loading" @click="getDeviceData">
|
||||
刷新设备
|
||||
@ -34,8 +41,8 @@
|
||||
<template #empty>
|
||||
<el-empty description="设备列表为空" />
|
||||
</template>
|
||||
<el-table-column prop="id" label="设备 ID" />
|
||||
<el-table-column prop="name" label="设备名称">
|
||||
<el-table-column prop="id" label="设备 ID" show-overflow-tooltip />
|
||||
<el-table-column prop="name" label="设备名称" show-overflow-tooltip>
|
||||
<template #default="{ row }">
|
||||
<div class="flex items-center">
|
||||
<el-tooltip
|
||||
@ -51,9 +58,9 @@
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="300" align="center">
|
||||
<el-table-column label="操作" width="350" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button type="primary" :loading="row.$loading" @click="handleStart(row)">
|
||||
<el-button type="primary" :loading="row.$loading" @click="handleMirror(row)">
|
||||
{{ row.$loading ? '镜像中' : '开始镜像' }}
|
||||
</el-button>
|
||||
<el-button type="default" @click="handleScreenUp(row)">
|
||||
@ -137,16 +144,37 @@ export default {
|
||||
}
|
||||
row.$stopLoading = false
|
||||
},
|
||||
async handleStart(row) {
|
||||
async handleMirror(row) {
|
||||
row.$loading = true
|
||||
try {
|
||||
await this.$scrcpy.shell(`--serial=${row.id}`)
|
||||
await this.$scrcpy.shell(`--serial=${row.id} ${this.addScrcpyConfigs()}`)
|
||||
}
|
||||
catch (error) {
|
||||
this.$message.warning(error.message)
|
||||
}
|
||||
row.$loading = false
|
||||
},
|
||||
addScrcpyConfigs() {
|
||||
const configs = storage.get('scrcpyCache') || {}
|
||||
const value = Object.entries(configs)
|
||||
.reduce((arr, [key, value]) => {
|
||||
if (!value) {
|
||||
return arr
|
||||
}
|
||||
if (typeof value === 'boolean') {
|
||||
arr.push(key)
|
||||
}
|
||||
else {
|
||||
arr.push(`${key}=${value}`)
|
||||
}
|
||||
return arr
|
||||
}, [])
|
||||
.join(' ')
|
||||
|
||||
console.log('addScrcpyConfigs.value', value)
|
||||
|
||||
return value
|
||||
},
|
||||
async getDeviceData() {
|
||||
this.loading = true
|
||||
await sleep()
|
||||
|
@ -13,9 +13,9 @@
|
||||
--el-color-primary-light-9: rgba(var(--color-primary-50), 1);
|
||||
|
||||
/* 字体大小 */
|
||||
--el-font-size-base: 12px;
|
||||
--el-font-size-small: 14px;
|
||||
--el-font-size-large: 16px;
|
||||
/* --el-font-size-base: 14px;
|
||||
--el-font-size-small: 16px;
|
||||
--el-font-size-large: 18px; */
|
||||
}
|
||||
|
||||
.el-tabs-flex {
|
||||
@ -30,6 +30,6 @@
|
||||
}
|
||||
|
||||
.el-tab-pane {
|
||||
@apply h-full;
|
||||
@apply h-full overflow-auto;
|
||||
}
|
||||
}
|
||||
|
21
src/renderer/src/styles/css/desktop.css
Normal file
21
src/renderer/src/styles/css/desktop.css
Normal file
@ -0,0 +1,21 @@
|
||||
html {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
/* 自定义滚动条的外观 */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background-color: theme('colors.gray.100');
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: theme('colors.gray.300');
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background-color: theme('colors.gray.500');
|
||||
}
|
@ -1 +1,2 @@
|
||||
import '@viarotel-org/design/styles/resets'
|
||||
import './desktop.css'
|
||||
|
Loading…
Reference in New Issue
Block a user