mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2024-11-23 23:21:02 +01:00
feat: 📸 Enhanced recording
This commit is contained in:
parent
9555f58df5
commit
7f10161ad7
91
.vscode/settings.json
vendored
91
.vscode/settings.json
vendored
@ -1,15 +1,67 @@
|
|||||||
{
|
{
|
||||||
|
"eslint.codeAction.showDocumentation": {
|
||||||
|
"enable": true
|
||||||
|
},
|
||||||
|
"eslint.format.enable": true,
|
||||||
|
"prettier.enable": false,
|
||||||
"editor.formatOnSave": false,
|
"editor.formatOnSave": false,
|
||||||
"editor.codeActionsOnSave": {
|
"editor.codeActionsOnSave": {
|
||||||
"source.fixAll.eslint": "explicit",
|
"source.fixAll.eslint": "explicit",
|
||||||
"source.organizeImports": "never"
|
"source.organizeImports": "never"
|
||||||
},
|
},
|
||||||
"eslint.format.enable": true,
|
"eslint.rules.customizations": [
|
||||||
"eslint.codeAction.showDocumentation": {
|
{
|
||||||
"enable": true
|
"rule": "style/*",
|
||||||
},
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "format/*",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-indent",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-spacing",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-spaces",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-order",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-dangle",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*-newline",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*quotes",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"rule": "*semi",
|
||||||
|
"severity": "off",
|
||||||
|
"fixable": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"eslint.validate": [
|
"eslint.validate": [
|
||||||
// "jsonc",
|
|
||||||
"javascript",
|
"javascript",
|
||||||
"javascriptreact",
|
"javascriptreact",
|
||||||
"typescript",
|
"typescript",
|
||||||
@ -18,19 +70,25 @@
|
|||||||
"html",
|
"html",
|
||||||
"markdown",
|
"markdown",
|
||||||
"json",
|
"json",
|
||||||
"yaml"
|
"jsonc",
|
||||||
|
"yaml",
|
||||||
|
"toml",
|
||||||
|
"xml",
|
||||||
|
"gql",
|
||||||
|
"graphql",
|
||||||
|
"astro",
|
||||||
|
"svelte",
|
||||||
|
"css",
|
||||||
|
"less",
|
||||||
|
"scss",
|
||||||
|
"pcss",
|
||||||
|
"postcss"
|
||||||
],
|
],
|
||||||
"[typescript]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"[javascript]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"[json]": {
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
||||||
},
|
|
||||||
"i18n-ally.localesPaths": ["src/locales/index.js", "src/locales/languages"],
|
|
||||||
"i18n-ally.sourceLanguage": "zh-CN",
|
"i18n-ally.sourceLanguage": "zh-CN",
|
||||||
|
"i18n-ally.localesPaths": [
|
||||||
|
"src/locales/index.js",
|
||||||
|
"src/locales/languages"
|
||||||
|
],
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.extract.ignored": [
|
"i18n-ally.extract.ignored": [
|
||||||
"Switch",
|
"Switch",
|
||||||
@ -52,5 +110,4 @@
|
|||||||
"cSpell.words": [
|
"cSpell.words": [
|
||||||
"bhsn"
|
"bhsn"
|
||||||
],
|
],
|
||||||
"common-intellisense.ui": []
|
|
||||||
}
|
}
|
11
README-CN.md
11
README-CN.md
@ -84,15 +84,18 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
|||||||
|
|
||||||
- 镜像
|
- 镜像
|
||||||
- 录制
|
- 录制
|
||||||
- OTG
|
- 录制相机
|
||||||
- 摄像
|
- 录制音频
|
||||||
|
- 相机
|
||||||
- 灵活启动
|
- 灵活启动
|
||||||
|
- OTG
|
||||||
|
|
||||||
### 设备交互栏
|
### 设备交互栏
|
||||||
|
|
||||||
- 切换键
|
- 切换键
|
||||||
- 主屏幕
|
- 主屏幕
|
||||||
- 返回键
|
- 返回键
|
||||||
|
- 关闭屏幕(实验性)
|
||||||
- 通知栏
|
- 通知栏
|
||||||
- 电源键
|
- 电源键
|
||||||
- 旋转屏幕
|
- 旋转屏幕
|
||||||
@ -312,6 +315,10 @@ Windows 及 Linux 端内部集成了 Gnirehtet, 用于提供 PC 到安卓设
|
|||||||
|
|
||||||
你需要自定义 `scrcpy` 以及 `adb` 的文件路径(确保具有可执行权限),如果用到反向供网则同样需要以同样方法配置 `gnirehtet`。
|
你需要自定义 `scrcpy` 以及 `adb` 的文件路径(确保具有可执行权限),如果用到反向供网则同样需要以同样方法配置 `gnirehtet`。
|
||||||
|
|
||||||
|
### Could not execute "adb start-server"
|
||||||
|
|
||||||
|
这可能是因为安装路径中包含中文或特殊字符导致的,请尝试更改安装路径。
|
||||||
|
|
||||||
## 获得帮助
|
## 获得帮助
|
||||||
|
|
||||||
> 因为是开源项目 全靠爱发电 所以支持有限 更新节奏不固定
|
> 因为是开源项目 全靠爱发电 所以支持有限 更新节奏不固定
|
||||||
|
11
README-RU.md
11
README-RU.md
@ -82,15 +82,18 @@ Gnirehtet встроен в приложения для Windows и Linux, что
|
|||||||
|
|
||||||
- Зеркалирование
|
- Зеркалирование
|
||||||
- Запись
|
- Запись
|
||||||
- OTG
|
- Запись с камеры
|
||||||
|
- Запись аудио
|
||||||
- Камера
|
- Камера
|
||||||
- Пользовательский
|
- Гибкий запуск
|
||||||
|
- OTG
|
||||||
|
|
||||||
### Панель взаимодействия с устройством
|
### Панель взаимодействия с устройством
|
||||||
|
|
||||||
- Переключатель
|
- Переключатель
|
||||||
- Домой
|
- Домой
|
||||||
- Назад
|
- Назад
|
||||||
|
- Выключение экрана (экспериментально)
|
||||||
- Уведомление
|
- Уведомление
|
||||||
- Питание
|
- Питание
|
||||||
- Поворот
|
- Поворот
|
||||||
@ -311,6 +314,10 @@ Gnirehtet встроен в приложения для Windows и Linux, что
|
|||||||
|
|
||||||
Вам нужно настроить пользовательские пути к файлам для `scrcpy` и `adb` (убедившись, что у них есть разрешения на выполнение). Если вы используете обратный тетеринг, аналогично настройте `gnirehtet`.
|
Вам нужно настроить пользовательские пути к файлам для `scrcpy` и `adb` (убедившись, что у них есть разрешения на выполнение). Если вы используете обратный тетеринг, аналогично настройте `gnirehtet`.
|
||||||
|
|
||||||
|
### Could not execute "adb start-server"
|
||||||
|
|
||||||
|
Это может быть вызвано наличием китайских или специальных символов в пути установки. Попробуйте изменить путь установки.
|
||||||
|
|
||||||
## Получение помощи
|
## Получение помощи
|
||||||
|
|
||||||
> Поскольку это проект с открытым исходным кодом, полностью поддерживаемый пожертвованиями, поддержка ограничена, и обновления могут не выходить по фиксированному расписанию.
|
> Поскольку это проект с открытым исходным кодом, полностью поддерживаемый пожертвованиями, поддержка ограничена, и обновления могут не выходить по фиксированному расписанию.
|
||||||
|
@ -82,15 +82,18 @@ Refer to [scrcpy/doc/shortcuts](https://github.com/Genymobile/scrcpy/blob/master
|
|||||||
|
|
||||||
- Mirror
|
- Mirror
|
||||||
- Recording
|
- Recording
|
||||||
- OTG
|
- Recording Camera
|
||||||
|
- Recording Audio
|
||||||
- Camera
|
- Camera
|
||||||
- Custom
|
- Custom
|
||||||
|
- OTG
|
||||||
|
|
||||||
### Device Interaction Bar
|
### Device Interaction Bar
|
||||||
|
|
||||||
- Switch
|
- Switch
|
||||||
- Home
|
- Home
|
||||||
- Back
|
- Back
|
||||||
|
- Turn off screen (experimental)
|
||||||
- Notification
|
- Notification
|
||||||
- Power
|
- Power
|
||||||
- Rotation
|
- Rotation
|
||||||
@ -311,6 +314,10 @@ Please try `disabling audio forwarding` feature through the `preferences setting
|
|||||||
|
|
||||||
You need to customize the file paths for `scrcpy` and `adb` (ensuring they have executable permissions). If using reverse tethering, configure `gnirehtet` similarly.
|
You need to customize the file paths for `scrcpy` and `adb` (ensuring they have executable permissions). If using reverse tethering, configure `gnirehtet` similarly.
|
||||||
|
|
||||||
|
### Could not execute "adb start-server"
|
||||||
|
|
||||||
|
This might be due to Chinese or special characters in the installation path. Please try changing the installation path.
|
||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
> As this is an open source project run entirely by donations, support is limited and updates may not be on a fixed schedule.
|
> As this is an open source project run entirely by donations, support is limited and updates may not be on a fixed schedule.
|
||||||
|
@ -63,7 +63,6 @@ import { i18n } from '$/locales/index.js'
|
|||||||
import localeModel from '$/plugins/element-plus/locale.js'
|
import localeModel from '$/plugins/element-plus/locale.js'
|
||||||
|
|
||||||
import { useDeviceStore, useThemeStore } from '$/store/index.js'
|
import { useDeviceStore, useThemeStore } from '$/store/index.js'
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
|
|
||||||
const themeStore = useThemeStore()
|
const themeStore = useThemeStore()
|
||||||
const deviceStore = useDeviceStore()
|
const deviceStore = useDeviceStore()
|
||||||
|
@ -10,7 +10,6 @@ export function initControlWindow(mainWindow) {
|
|||||||
|
|
||||||
const controlWindow = new BrowserWindow({
|
const controlWindow = new BrowserWindow({
|
||||||
icon: getLogoPath(),
|
icon: getLogoPath(),
|
||||||
parent: mainWindow,
|
|
||||||
width: 700,
|
width: 700,
|
||||||
minWidth: 700,
|
minWidth: 700,
|
||||||
height: 28,
|
height: 28,
|
||||||
|
16
package.json
16
package.json
@ -27,7 +27,7 @@
|
|||||||
"vue": "3.4.21"
|
"vue": "3.4.21"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@antfu/eslint-config": "3.3.2",
|
"@antfu/eslint-config": "3.8.0",
|
||||||
"@devicefarmer/adbkit": "3.2.6",
|
"@devicefarmer/adbkit": "3.2.6",
|
||||||
"@electron-toolkit/preload": "3.0.1",
|
"@electron-toolkit/preload": "3.0.1",
|
||||||
"@electron-toolkit/utils": "3.0.0",
|
"@electron-toolkit/utils": "3.0.0",
|
||||||
@ -39,15 +39,15 @@
|
|||||||
"@vitejs/plugin-vue": "5.0.4",
|
"@vitejs/plugin-vue": "5.0.4",
|
||||||
"@vueuse/core": "10.9.0",
|
"@vueuse/core": "10.9.0",
|
||||||
"dayjs": "1.11.11",
|
"dayjs": "1.11.11",
|
||||||
"electron": "29.1.1",
|
"electron": "33.0.2",
|
||||||
"electron-builder": "24.13.3",
|
"electron-builder": "25.1.8",
|
||||||
"electron-context-menu": "4.0.4",
|
"electron-context-menu": "4.0.4",
|
||||||
"electron-find-in-page": "1.0.8",
|
"electron-find-in-page": "1.0.8",
|
||||||
"electron-log": "5.2.0",
|
"electron-log": "5.2.0",
|
||||||
"electron-store": "9.0.0",
|
"electron-store": "9.0.0",
|
||||||
"electron-updater": "6.1.8",
|
"electron-updater": "6.3.9",
|
||||||
"element-plus": "2.8.2",
|
"element-plus": "2.8.2",
|
||||||
"eslint": "9.10.0",
|
"eslint": "9.13.0",
|
||||||
"fix-path": "4.0.0",
|
"fix-path": "4.0.0",
|
||||||
"fs-extra": "11.2.0",
|
"fs-extra": "11.2.0",
|
||||||
"husky": "9.0.11",
|
"husky": "9.0.11",
|
||||||
@ -59,11 +59,11 @@
|
|||||||
"rimraf": "^6.0.1",
|
"rimraf": "^6.0.1",
|
||||||
"simple-git": "^3.27.0",
|
"simple-git": "^3.27.0",
|
||||||
"unocss": "0.62.3",
|
"unocss": "0.62.3",
|
||||||
"unplugin-auto-import": "0.18.2",
|
"unplugin-auto-import": "0.18.3",
|
||||||
"unplugin-vue-components": "0.27.4",
|
"unplugin-vue-components": "0.27.4",
|
||||||
"vite": "5.1.5",
|
"vite": "5.1.5",
|
||||||
"vite-plugin-electron": "0.28.7",
|
"vite-plugin-electron": "0.28.8",
|
||||||
"vite-plugin-electron-renderer": "0.14.5",
|
"vite-plugin-electron-renderer": "0.14.6",
|
||||||
"vite-svg-loader": "5.1.0",
|
"vite-svg-loader": "5.1.0",
|
||||||
"vue-command": "35.2.1",
|
"vue-command": "35.2.1",
|
||||||
"vue-i18n": "9.13.1",
|
"vue-i18n": "9.13.1",
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import { sleep } from '$/utils'
|
import { sleep } from '$/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
row: {
|
row: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -14,6 +14,7 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
DeployDialog,
|
DeployDialog,
|
||||||
},
|
},
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
row: {
|
row: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import { sleep } from '$/utils'
|
import { sleep } from '$/utils'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
row: {
|
row: {
|
||||||
type: Object,
|
type: Object,
|
||||||
|
@ -6,8 +6,31 @@
|
|||||||
import { sleep } from '$/utils'
|
import { sleep } from '$/utils'
|
||||||
import { openFloatControl } from '$/utils/device/index.js'
|
import { openFloatControl } from '$/utils/device/index.js'
|
||||||
|
|
||||||
|
const recordModel = {
|
||||||
|
default: {
|
||||||
|
excludes: '',
|
||||||
|
command: '',
|
||||||
|
extname: config => config['--record-format'] || 'mp4',
|
||||||
|
},
|
||||||
|
audio: {
|
||||||
|
excludes: ['--video-source', '--no-audio', '--mouse'],
|
||||||
|
commands: ['--no-video', '--mouse=disabled'],
|
||||||
|
extname: config => config['--audio-record-format'] || 'opus',
|
||||||
|
},
|
||||||
|
camera: {
|
||||||
|
excludes: ['--video-source'],
|
||||||
|
commands: ['--video-source=camera'],
|
||||||
|
extname: config => config['--record-format'] || 'mp4',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
|
recordType: {
|
||||||
|
type: String,
|
||||||
|
default: 'default',
|
||||||
|
},
|
||||||
row: {
|
row: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
@ -22,6 +45,11 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
activeModel() {
|
||||||
|
return recordModel[this.recordType]
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async handleClick() {
|
async handleClick() {
|
||||||
const row = this.row
|
const row = this.row
|
||||||
@ -32,25 +60,36 @@ export default {
|
|||||||
|
|
||||||
const savePath = this.getRecordPath(row)
|
const savePath = this.getRecordPath(row)
|
||||||
|
|
||||||
const args = this.$store.preference.scrcpyParameter(row.id, {
|
let args = this.$store.preference.scrcpyParameter(row.id, {
|
||||||
isRecord: true,
|
isRecord: ['default', 'audio'].includes(this.recordType),
|
||||||
excludes: ['--otg', '--mouse=aoa', '--keyboard=aoa', '--show-touches'],
|
isCamera: ['camera'].includes(this.recordType),
|
||||||
|
excludes: [
|
||||||
|
'--otg',
|
||||||
|
'--mouse=aoa',
|
||||||
|
'--keyboard=aoa',
|
||||||
|
'--show-touches',
|
||||||
|
...this.activeModel.excludes,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
args += ` ${this.activeModel.commands.join(' ')}`
|
||||||
|
|
||||||
|
console.log('args', args)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const recording = this.$scrcpy.record(row.id, {
|
const recording = this.$scrcpy.record(row.id, {
|
||||||
title: this.$store.device.getLabel(row, 'recording'),
|
title: this.$store.device.getLabel(row, 'recording'),
|
||||||
savePath,
|
savePath,
|
||||||
args,
|
args,
|
||||||
stdout: this.onStdout,
|
|
||||||
stderr: this.onStderr,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
await sleep(1 * 1000)
|
await sleep(1 * 1000)
|
||||||
|
|
||||||
this.loading = false
|
this.loading = false
|
||||||
|
|
||||||
openFloatControl(toRaw(this.row))
|
if (['default'].includes(this.$props.type)) {
|
||||||
|
openFloatControl(toRaw(this.row))
|
||||||
|
}
|
||||||
|
|
||||||
await recording
|
await recording
|
||||||
|
|
||||||
@ -65,20 +104,21 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onStdout() {},
|
|
||||||
onStderr() {},
|
|
||||||
getRecordPath(row) {
|
getRecordPath(row) {
|
||||||
const config = this.$store.preference.getData(row.id)
|
const deviceConfig = this.$store.preference.getData(this.row.id)
|
||||||
const basePath = config.savePath
|
|
||||||
const extension = config['--record-format'] || 'mp4'
|
const savePath = deviceConfig.savePath
|
||||||
|
|
||||||
|
const extension = this.activeModel.extname(deviceConfig)
|
||||||
|
|
||||||
const fileName = this.$store.device.getLabel(
|
const fileName = this.$store.device.getLabel(
|
||||||
row,
|
row,
|
||||||
({ time }) => `record-${time}.${extension}`,
|
({ time }) => `record-${time}.${extension}`,
|
||||||
)
|
)
|
||||||
|
|
||||||
const joinValue = this.$path.join(basePath, fileName)
|
const filePath = this.$path.join(savePath, fileName)
|
||||||
const value = this.$path.normalize(joinValue)
|
|
||||||
|
const value = this.$path.normalize(filePath)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
},
|
},
|
||||||
|
@ -1,96 +0,0 @@
|
|||||||
<template>
|
|
||||||
<slot :loading="loading" :trigger="handleClick" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { sleep } from '$/utils'
|
|
||||||
import { openFloatControl } from '$/utils/device/index.js'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
row: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
toggleRowExpansion: {
|
|
||||||
type: Function,
|
|
||||||
default: () => () => false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async handleClick() {
|
|
||||||
const row = this.row
|
|
||||||
|
|
||||||
this.loading = true
|
|
||||||
|
|
||||||
this.toggleRowExpansion(row, true)
|
|
||||||
|
|
||||||
const savePath = this.getRecordPath(row)
|
|
||||||
|
|
||||||
let args = this.$store.preference.scrcpyParameter(row.id, {
|
|
||||||
isRecord: true,
|
|
||||||
excludes: ['--otg', '--mouse=aoa', '--keyboard=aoa', '--video-source', '--show-touches'],
|
|
||||||
})
|
|
||||||
|
|
||||||
args += ' --video-source=camera'
|
|
||||||
|
|
||||||
try {
|
|
||||||
const recording = this.$scrcpy.record(row.id, {
|
|
||||||
title: this.$store.device.getLabel(row, 'recording'),
|
|
||||||
savePath,
|
|
||||||
args,
|
|
||||||
stdout: this.onStdout,
|
|
||||||
stderr: this.onStderr,
|
|
||||||
})
|
|
||||||
|
|
||||||
await sleep(1 * 1000)
|
|
||||||
|
|
||||||
this.loading = false
|
|
||||||
|
|
||||||
openFloatControl(toRaw(this.row))
|
|
||||||
|
|
||||||
await recording
|
|
||||||
|
|
||||||
await this.handleSuccess(savePath)
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error('record.args', args)
|
|
||||||
console.error('record.error', error)
|
|
||||||
|
|
||||||
if (error.message) {
|
|
||||||
this.$message.warning(error.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onStdout() {},
|
|
||||||
onStderr() {},
|
|
||||||
getRecordPath(row) {
|
|
||||||
const config = this.$store.preference.getData(row.id)
|
|
||||||
const basePath = config.savePath
|
|
||||||
const extension = config['--record-format'] || 'mp4'
|
|
||||||
|
|
||||||
const fileName = this.$store.device.getLabel(
|
|
||||||
row,
|
|
||||||
({ time }) => `record-${time}.${extension}`,
|
|
||||||
)
|
|
||||||
|
|
||||||
const joinValue = this.$path.join(basePath, fileName)
|
|
||||||
const value = this.$path.normalize(joinValue)
|
|
||||||
|
|
||||||
return value
|
|
||||||
},
|
|
||||||
async handleSuccess(savePath) {
|
|
||||||
return this.$message.success(
|
|
||||||
`${this.$t('device.record.success.title')}: ${savePath}`,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style></style>
|
|
@ -17,6 +17,7 @@
|
|||||||
:key="index"
|
:key="index"
|
||||||
v-bind="{
|
v-bind="{
|
||||||
...$props,
|
...$props,
|
||||||
|
...(item.props || {}),
|
||||||
}"
|
}"
|
||||||
v-slot="{ loading, trigger }"
|
v-slot="{ loading, trigger }"
|
||||||
>
|
>
|
||||||
@ -40,7 +41,6 @@
|
|||||||
<script>
|
<script>
|
||||||
import Record from './components/Record/index.vue'
|
import Record from './components/Record/index.vue'
|
||||||
import Camera from './components/Camera/index.vue'
|
import Camera from './components/Camera/index.vue'
|
||||||
import RecordCamera from './components/RecordCamera/index.vue'
|
|
||||||
import Otg from './components/Otg/index.vue'
|
import Otg from './components/Otg/index.vue'
|
||||||
import Custom from './components/Custom/index.vue'
|
import Custom from './components/Custom/index.vue'
|
||||||
|
|
||||||
@ -48,7 +48,6 @@ export default {
|
|||||||
components: {
|
components: {
|
||||||
Record,
|
Record,
|
||||||
Camera,
|
Camera,
|
||||||
RecordCamera,
|
|
||||||
Otg,
|
Otg,
|
||||||
Custom,
|
Custom,
|
||||||
},
|
},
|
||||||
@ -66,12 +65,22 @@ export default {
|
|||||||
component: 'Record',
|
component: 'Record',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'device.actions.more.camera.name',
|
label: 'device.actions.more.recordCamera.name',
|
||||||
component: 'Camera',
|
component: 'Record',
|
||||||
|
props: {
|
||||||
|
recordType: 'camera',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'device.actions.more.recordCamera.name',
|
label: 'device.actions.more.recordAudio.name',
|
||||||
component: 'RecordCamera',
|
component: 'Record',
|
||||||
|
props: {
|
||||||
|
recordType: 'audio',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'device.actions.more.camera.name',
|
||||||
|
component: 'Camera',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'device.actions.more.otg.name',
|
label: 'device.actions.more.otg.name',
|
||||||
|
@ -253,21 +253,21 @@ export default {
|
|||||||
await this.$confirm(
|
await this.$confirm(
|
||||||
`<div class="pt-4 pl-4">
|
`<div class="pt-4 pl-4">
|
||||||
<div class="text-sm text-red-500 pb-4">${this.$t(
|
<div class="text-sm text-red-500 pb-4">${this.$t(
|
||||||
'device.wireless.connect.error.detail',
|
'device.wireless.connect.error.detail',
|
||||||
)}:${message}</div>
|
)}:${message}</div>
|
||||||
<div>${this.$t('device.wireless.connect.error.reasons[0]')}:</div>
|
<div>${this.$t('device.wireless.connect.error.reasons[0]')}:</div>
|
||||||
<div>1. ${this.$t(
|
<div>1. ${this.$t(
|
||||||
'device.wireless.connect.error.reasons[1]',
|
'device.wireless.connect.error.reasons[1]',
|
||||||
)} </div>
|
)} </div>
|
||||||
<div>2. ${this.$t(
|
<div>2. ${this.$t(
|
||||||
'device.wireless.connect.error.reasons[2]',
|
'device.wireless.connect.error.reasons[2]',
|
||||||
)} </div>
|
)} </div>
|
||||||
<div>3. ${this.$t(
|
<div>3. ${this.$t(
|
||||||
'device.wireless.connect.error.reasons[3]',
|
'device.wireless.connect.error.reasons[3]',
|
||||||
)} </div>
|
)} </div>
|
||||||
<div>4. ${this.$t(
|
<div>4. ${this.$t(
|
||||||
'device.wireless.connect.error.reasons[4]',
|
'device.wireless.connect.error.reasons[4]',
|
||||||
)} </div>
|
)} </div>
|
||||||
</div>`,
|
</div>`,
|
||||||
this.$t('device.wireless.connect.error.title'),
|
this.$t('device.wireless.connect.error.title'),
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-select
|
<el-select
|
||||||
v-bind="{ ...(data.props || {}) }"
|
v-bind="{ clearable: true, ...(data.props || {}) }"
|
||||||
v-model="selectValue"
|
v-model="selectValue"
|
||||||
class="!w-full"
|
class="!w-full"
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-select
|
<el-select
|
||||||
v-bind="{
|
v-bind="{
|
||||||
|
clearable: true,
|
||||||
...(data.props || {}),
|
...(data.props || {}),
|
||||||
}"
|
}"
|
||||||
v-model="selectValue"
|
v-model="selectValue"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-select
|
<el-select
|
||||||
v-bind="{ ...(data.props || {}) }"
|
v-bind="{ clearable: true, ...(data.props || {}) }"
|
||||||
v-model="selectValue"
|
v-model="selectValue"
|
||||||
class="!w-full"
|
class="!w-full"
|
||||||
>
|
>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-form ref="elForm" :model="preferenceData" label-width="225px" class="">
|
<el-form ref="elForm" :model="preferenceData" label-width="250px" class="">
|
||||||
<el-collapse
|
<el-collapse
|
||||||
v-model="collapseValue"
|
v-model="collapseValue"
|
||||||
v-bind="{
|
v-bind="{
|
||||||
@ -31,61 +31,52 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="pt-4">
|
<div class="pr-8 pt-4">
|
||||||
<el-form
|
<el-row :gutter="20">
|
||||||
ref="elForm"
|
<el-col
|
||||||
:model="preferenceData"
|
v-for="(item_1, name_1) of subModel(item)"
|
||||||
label-width="250px"
|
:key="name_1"
|
||||||
class="pr-8 pt-4"
|
:span="item_1.span || 12"
|
||||||
>
|
:offset="item_1.offset || 0"
|
||||||
<el-row :gutter="20">
|
>
|
||||||
<el-col
|
<el-form-item :label="$t(item_1.label)" :prop="item_1.field">
|
||||||
v-for="(item_1, name_1) of subModel(item)"
|
<template #label>
|
||||||
:key="name_1"
|
<div class="flex items-center">
|
||||||
:span="item_1.span || 12"
|
<el-tooltip
|
||||||
:offset="item_1.offset || 0"
|
v-if="item_1.tips"
|
||||||
>
|
popper-class="max-w-96"
|
||||||
<el-form-item :label="$t(item_1.label)" :prop="item_1.field">
|
effect="dark"
|
||||||
<template #label>
|
:content="$t(item_1.tips)"
|
||||||
<div class="flex items-center">
|
placement="bottom"
|
||||||
<el-tooltip
|
>
|
||||||
v-if="item_1.tips"
|
<el-link
|
||||||
popper-class="max-w-96"
|
class="mr-1 !text-base"
|
||||||
effect="dark"
|
icon="InfoFilled"
|
||||||
:content="$t(item_1.tips)"
|
type="warning"
|
||||||
placement="bottom"
|
:underline="false"
|
||||||
>
|
>
|
||||||
<el-link
|
</el-link>
|
||||||
class="mr-1 !text-base"
|
</el-tooltip>
|
||||||
icon="InfoFilled"
|
<div class="truncate max-w-56" :title="$t(item_1.label)">
|
||||||
type="warning"
|
{{ $t(item_1.label) }}
|
||||||
:underline="false"
|
|
||||||
>
|
|
||||||
</el-link>
|
|
||||||
</el-tooltip>
|
|
||||||
<div class="truncate max-w-56" :title="$t(item_1.label)">
|
|
||||||
{{
|
|
||||||
$t(item_1.label)
|
|
||||||
}}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<component
|
<component
|
||||||
:is="inputModel[item_1.type]"
|
:is="inputModel[item_1.type]"
|
||||||
v-model="preferenceData[item_1.field]"
|
v-model="preferenceData[item_1.field]"
|
||||||
v-bind="{
|
v-bind="{
|
||||||
preferenceData,
|
preferenceData,
|
||||||
deviceScope,
|
deviceScope,
|
||||||
title: $t(item_1.placeholder),
|
title: $t(item_1.placeholder),
|
||||||
placeholder: $t(item_1.placeholder),
|
placeholder: $t(item_1.placeholder),
|
||||||
data: item_1,
|
data: item_1,
|
||||||
}"
|
}"
|
||||||
></component>
|
></component>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</el-form>
|
|
||||||
</div>
|
</div>
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
@ -93,9 +84,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
|
import { i18n } from '$/locales/index.js'
|
||||||
|
|
||||||
import { usePreferenceStore } from '$/store/index.js'
|
import { usePreferenceStore } from '$/store/index.js'
|
||||||
|
|
||||||
import { omit } from 'lodash-es'
|
import { omit } from 'lodash-es'
|
||||||
|
import { computed } from 'vue'
|
||||||
|
|
||||||
import { inputModel } from './components/index.js'
|
import { inputModel } from './components/index.js'
|
||||||
|
|
||||||
@ -114,6 +108,8 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const locale = computed(() => i18n.global.locale.value)
|
||||||
|
|
||||||
const preferenceData = defineModel('modelValue', {
|
const preferenceData = defineModel('modelValue', {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"device.actions.more.record.name": "Start Recording",
|
"device.actions.more.record.name": "Start Recording",
|
||||||
"device.actions.more.camera.name": "Startup Camera",
|
"device.actions.more.camera.name": "Startup Camera",
|
||||||
"device.actions.more.recordCamera.name": "Record Camera",
|
"device.actions.more.recordCamera.name": "Record Camera",
|
||||||
|
"device.actions.more.recordAudio.name": "Record Audio",
|
||||||
"device.actions.more.otg.name": "Startup OTG",
|
"device.actions.more.otg.name": "Startup OTG",
|
||||||
"device.actions.more.custom.name": "Custom Startup",
|
"device.actions.more.custom.name": "Custom Startup",
|
||||||
|
|
||||||
@ -317,9 +318,11 @@
|
|||||||
|
|
||||||
"preferences.record.name": "Recording",
|
"preferences.record.name": "Recording",
|
||||||
"preferences.record.format.name": "Format",
|
"preferences.record.format.name": "Format",
|
||||||
|
"preferences.record.format.placeholder": "mp4",
|
||||||
|
"preferences.record.format.audio.name": "Audio Format",
|
||||||
|
"preferences.record.format.audio.placeholder": "opus",
|
||||||
"preferences.record.time-limit.name": "Recording Time Limit",
|
"preferences.record.time-limit.name": "Recording Time Limit",
|
||||||
"preferences.record.time-limit.placeholder": "No time limit",
|
"preferences.record.time-limit.placeholder": "No time limit",
|
||||||
"preferences.record.format.placeholder": "mp4",
|
|
||||||
"preferences.record.lock-video-orientation.name": "Video Direction",
|
"preferences.record.lock-video-orientation.name": "Video Direction",
|
||||||
"preferences.record.lock-video-orientation.placeholder": "Device Orientation",
|
"preferences.record.lock-video-orientation.placeholder": "Device Orientation",
|
||||||
"preferences.record.no-video-playback.name": "Disable Video Playback",
|
"preferences.record.no-video-playback.name": "Disable Video Playback",
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"device.actions.more.record.name": "Начать запись",
|
"device.actions.more.record.name": "Начать запись",
|
||||||
"device.actions.more.camera.name": "Запустить камеры",
|
"device.actions.more.camera.name": "Запустить камеры",
|
||||||
"device.actions.more.recordCamera.name": "Запись камеры",
|
"device.actions.more.recordCamera.name": "Запись камеры",
|
||||||
|
"device.actions.more.recordAudio.name": "Записать аудио",
|
||||||
"device.actions.more.otg.name": "Запустить OTG",
|
"device.actions.more.otg.name": "Запустить OTG",
|
||||||
"device.actions.more.custom.name": "Пользовательский запуск",
|
"device.actions.more.custom.name": "Пользовательский запуск",
|
||||||
|
|
||||||
@ -317,9 +318,11 @@
|
|||||||
|
|
||||||
"preferences.record.name": "Запись",
|
"preferences.record.name": "Запись",
|
||||||
"preferences.record.format.name": "Формат",
|
"preferences.record.format.name": "Формат",
|
||||||
|
"preferences.record.format.placeholder": "mp4",
|
||||||
|
"preferences.record.format.audio.name": "Аудио формат",
|
||||||
|
"preferences.record.format.audio.placeholder": "opus",
|
||||||
"preferences.record.time-limit.name": "Ограничение времени записи",
|
"preferences.record.time-limit.name": "Ограничение времени записи",
|
||||||
"preferences.record.time-limit.placeholder": "Без ограничения времени",
|
"preferences.record.time-limit.placeholder": "Без ограничения времени",
|
||||||
"preferences.record.format.placeholder": "mp4",
|
|
||||||
"preferences.record.lock-video-orientation.name": "Ориентация видео",
|
"preferences.record.lock-video-orientation.name": "Ориентация видео",
|
||||||
"preferences.record.lock-video-orientation.placeholder": "Ориентация устройства",
|
"preferences.record.lock-video-orientation.placeholder": "Ориентация устройства",
|
||||||
"preferences.record.no-video-playback.name": "Отключить воспроизведение видео",
|
"preferences.record.no-video-playback.name": "Отключить воспроизведение видео",
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"device.actions.more.record.name": "开始录制",
|
"device.actions.more.record.name": "开始录制",
|
||||||
"device.actions.more.camera.name": "启动相机",
|
"device.actions.more.camera.name": "启动相机",
|
||||||
"device.actions.more.recordCamera.name": "录制相机",
|
"device.actions.more.recordCamera.name": "录制相机",
|
||||||
|
"device.actions.more.recordAudio.name": "录制音频",
|
||||||
"device.actions.more.otg.name": "启动OTG",
|
"device.actions.more.otg.name": "启动OTG",
|
||||||
"device.actions.more.custom.name": "灵活启动",
|
"device.actions.more.custom.name": "灵活启动",
|
||||||
|
|
||||||
@ -316,8 +317,10 @@
|
|||||||
"preferences.window.position.y.placeholder": "相对于桌面中心",
|
"preferences.window.position.y.placeholder": "相对于桌面中心",
|
||||||
|
|
||||||
"preferences.record.name": "音视频录制",
|
"preferences.record.name": "音视频录制",
|
||||||
"preferences.record.format.name": "录制视频格式",
|
"preferences.record.format.name": "视频格式",
|
||||||
"preferences.record.format.placeholder": "mp4",
|
"preferences.record.format.placeholder": "mp4",
|
||||||
|
"preferences.record.format.audio.name": "音频格式",
|
||||||
|
"preferences.record.format.audio.placeholder": "opus",
|
||||||
"preferences.record.time-limit.name": "录制时长",
|
"preferences.record.time-limit.name": "录制时长",
|
||||||
"preferences.record.time-limit.placeholder": "不限时长",
|
"preferences.record.time-limit.placeholder": "不限时长",
|
||||||
"preferences.record.lock-video-orientation.name": "录制视频方向",
|
"preferences.record.lock-video-orientation.name": "录制视频方向",
|
||||||
|
@ -129,6 +129,7 @@
|
|||||||
"device.actions.more.record.name": "開始錄製",
|
"device.actions.more.record.name": "開始錄製",
|
||||||
"device.actions.more.camera.name": "啟動鏡頭",
|
"device.actions.more.camera.name": "啟動鏡頭",
|
||||||
"device.actions.more.recordCamera.name": "錄製鏡頭",
|
"device.actions.more.recordCamera.name": "錄製鏡頭",
|
||||||
|
"device.actions.more.recordAudio.name": "錄製音訊",
|
||||||
"device.actions.more.otg.name": "啟動 OTG",
|
"device.actions.more.otg.name": "啟動 OTG",
|
||||||
"device.actions.more.custom.name": "靈活啟動",
|
"device.actions.more.custom.name": "靈活啟動",
|
||||||
|
|
||||||
@ -316,8 +317,10 @@
|
|||||||
"preferences.window.position.y.placeholder": "相對於桌面中心",
|
"preferences.window.position.y.placeholder": "相對於桌面中心",
|
||||||
|
|
||||||
"preferences.record.name": "影片錄製",
|
"preferences.record.name": "影片錄製",
|
||||||
"preferences.record.format.name": "錄製影片格式",
|
"preferences.record.format.name": "影片格式",
|
||||||
"preferences.record.format.placeholder": "mp4",
|
"preferences.record.format.placeholder": "mp4",
|
||||||
|
"preferences.record.format.audio.name": "音訊格式",
|
||||||
|
"preferences.record.format.audio.placeholder": "opus",
|
||||||
"preferences.record.time-limit.name": "錄製時長",
|
"preferences.record.time-limit.name": "錄製時長",
|
||||||
"preferences.record.time-limit.placeholder": "不限時長",
|
"preferences.record.time-limit.placeholder": "不限時長",
|
||||||
"preferences.record.lock-video-orientation.name": "錄製影片方向",
|
"preferences.record.lock-video-orientation.name": "錄製影片方向",
|
||||||
|
@ -46,6 +46,7 @@ export const usePreferenceStore = defineStore({
|
|||||||
'--video-code',
|
'--video-code',
|
||||||
'--audio-code',
|
'--audio-code',
|
||||||
'--keyboard-inject',
|
'--keyboard-inject',
|
||||||
|
'--audio-record-format',
|
||||||
...getOtherFields('scrcpy'),
|
...getOtherFields('scrcpy'),
|
||||||
],
|
],
|
||||||
recordKeys,
|
recordKeys,
|
||||||
|
@ -19,6 +19,39 @@ export default {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
audioRecordFormat: {
|
||||||
|
label: 'preferences.record.format.audio.name',
|
||||||
|
field: '--audio-record-format',
|
||||||
|
type: 'Select',
|
||||||
|
value: void 0,
|
||||||
|
placeholder: 'preferences.record.format.audio.placeholder',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'opus',
|
||||||
|
value: 'opus',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'wav',
|
||||||
|
value: 'wav',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'mka',
|
||||||
|
value: 'mka',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'flac',
|
||||||
|
value: 'flac',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'aac',
|
||||||
|
value: 'aac',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'm4a',
|
||||||
|
value: 'm4a',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
lockVideoOrientation: {
|
lockVideoOrientation: {
|
||||||
label: 'preferences.record.lock-video-orientation.name',
|
label: 'preferences.record.lock-video-orientation.name',
|
||||||
field: '--lock-video-orientation',
|
field: '--lock-video-orientation',
|
||||||
|
Loading…
Reference in New Issue
Block a user