installed windows client save incoming recording to a specific directory (#7974)

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2024-05-08 17:04:53 +08:00 committed by GitHub
parent 35832f8f7f
commit 09f3850250
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
51 changed files with 173 additions and 45 deletions

View File

@ -485,42 +485,72 @@ class _GeneralState extends State<_General> {
} }
Widget record(BuildContext context) { Widget record(BuildContext context) {
final showRootDir = isWindows && bind.mainIsInstalled();
return futureBuilder(future: () async { return futureBuilder(future: () async {
String defaultDirectory = await bind.mainDefaultVideoSaveDirectory(); String user_dir = await bind.mainVideoSaveDirectory(root: false);
String root_dir =
showRootDir ? await bind.mainVideoSaveDirectory(root: true) : '';
bool user_dir_exists = await Directory(user_dir).exists();
bool root_dir_exists =
showRootDir ? await Directory(root_dir).exists() : false;
// canLaunchUrl blocked on windows portable, user SYSTEM // canLaunchUrl blocked on windows portable, user SYSTEM
return {'dir': defaultDirectory, 'canlaunch': true}; return {
'user_dir': user_dir,
'root_dir': root_dir,
'user_dir_exists': user_dir_exists,
'root_dir_exists': root_dir_exists,
};
}(), hasData: (data) { }(), hasData: (data) {
Map<String, dynamic> map = data as Map<String, dynamic>; Map<String, dynamic> map = data as Map<String, dynamic>;
String dir = map['dir']!; String user_dir = map['user_dir']!;
String customDirectory = String root_dir = map['root_dir']!;
bind.mainGetOptionSync(key: 'video-save-directory'); bool root_dir_exists = map['root_dir_exists']!;
if (customDirectory.isNotEmpty) { bool user_dir_exists = map['user_dir_exists']!;
dir = customDirectory;
}
bool canlaunch = map['canlaunch']! as bool;
return _Card(title: 'Recording', children: [ return _Card(title: 'Recording', children: [
_OptionCheckBox(context, 'Automatically record incoming sessions', _OptionCheckBox(context, 'Automatically record incoming sessions',
'allow-auto-record-incoming'), 'allow-auto-record-incoming'),
if (showRootDir)
Row(
children: [
Text('${translate("Incoming")}:'),
Expanded(
child: GestureDetector(
onTap: root_dir_exists
? () => launchUrl(Uri.file(root_dir))
: null,
child: Text(
root_dir,
softWrap: true,
style: root_dir_exists
? const TextStyle(
decoration: TextDecoration.underline)
: null,
)).marginOnly(left: 10),
),
],
).marginOnly(left: _kContentHMargin),
Row( Row(
children: [ children: [
Text('${translate("Directory")}:'), Text('${translate(showRootDir ? "Outgoing" : "Directory")}:'),
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
onTap: canlaunch ? () => launchUrl(Uri.file(dir)) : null, onTap: user_dir_exists
? () => launchUrl(Uri.file(user_dir))
: null,
child: Text( child: Text(
dir, user_dir,
softWrap: true, softWrap: true,
style: style: user_dir_exists
const TextStyle(decoration: TextDecoration.underline), ? const TextStyle(decoration: TextDecoration.underline)
: null,
)).marginOnly(left: 10), )).marginOnly(left: 10),
), ),
ElevatedButton( ElevatedButton(
onPressed: () async { onPressed: () async {
String? initialDirectory; String? initialDirectory;
if (await Directory.fromUri(Uri.directory(dir)) if (await Directory.fromUri(Uri.directory(user_dir))
.exists()) { .exists()) {
initialDirectory = dir; initialDirectory = user_dir;
} }
String? selectedDirectory = await FilePicker.platform String? selectedDirectory = await FilePicker.platform
.getDirectoryPath(initialDirectory: initialDirectory); .getDirectoryPath(initialDirectory: initialDirectory);

View File

@ -525,7 +525,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
builder: (ctx, data) => Offstage( builder: (ctx, data) => Offstage(
offstage: !data.hasData, offstage: !data.hasData,
child: Text("${translate("Directory")}: ${data.data}")), child: Text("${translate("Directory")}: ${data.data}")),
future: bind.mainDefaultVideoSaveDirectory()), future: bind.mainVideoSaveDirectory(root: false)),
initialValue: _autoRecordIncomingSession, initialValue: _autoRecordIncomingSession,
onToggle: (v) async { onToggle: (v) async {
await bind.mainSetOption( await bind.mainSetOption(

View File

@ -943,7 +943,7 @@ class RustdeskImpl {
throw UnimplementedError(); throw UnimplementedError();
} }
Future<String> mainDefaultVideoSaveDirectory({dynamic hint}) { Future<String> mainVideoSaveDirectory({required bool root, dynamic hint}) {
throw UnimplementedError(); throw UnimplementedError();
} }

View File

@ -26,7 +26,7 @@ const MIN_SECS: u64 = 1;
pub struct RecorderContext { pub struct RecorderContext {
pub server: bool, pub server: bool,
pub id: String, pub id: String,
pub default_dir: String, pub dir: String,
pub filename: String, pub filename: String,
pub width: usize, pub width: usize,
pub height: usize, pub height: usize,
@ -36,18 +36,11 @@ pub struct RecorderContext {
impl RecorderContext { impl RecorderContext {
pub fn set_filename(&mut self) -> ResultType<()> { pub fn set_filename(&mut self) -> ResultType<()> {
let mut dir = Config::get_option("video-save-directory"); if !PathBuf::from(&self.dir).exists() {
if !dir.is_empty() { std::fs::create_dir_all(&self.dir)?;
if !PathBuf::from(&dir).exists() {
std::fs::create_dir_all(&dir)?;
}
} else {
dir = self.default_dir.clone();
if !dir.is_empty() && !PathBuf::from(&dir).exists() {
std::fs::create_dir_all(&dir)?;
}
} }
let file = if self.server { "s" } else { "c" }.to_string() let file = if self.server { "incoming" } else { "outgoing" }.to_string()
+ "_"
+ &self.id.clone() + &self.id.clone()
+ &chrono::Local::now().format("_%Y%m%d%H%M%S%3f_").to_string() + &chrono::Local::now().format("_%Y%m%d%H%M%S%3f_").to_string()
+ &self.format.to_string().to_lowercase() + &self.format.to_string().to_lowercase()
@ -59,7 +52,10 @@ impl RecorderContext {
} else { } else {
".mp4" ".mp4"
}; };
self.filename = PathBuf::from(&dir).join(file).to_string_lossy().to_string(); self.filename = PathBuf::from(&self.dir)
.join(file)
.to_string_lossy()
.to_string();
log::info!("video will save to {}", self.filename); log::info!("video will save to {}", self.filename);
Ok(()) Ok(())
} }

View File

@ -1112,7 +1112,7 @@ impl VideoHandler {
self.recorder = Recorder::new(RecorderContext { self.recorder = Recorder::new(RecorderContext {
server: false, server: false,
id, id,
default_dir: crate::ui_interface::default_video_save_directory(), dir: crate::ui_interface::video_save_directory(false),
filename: "".to_owned(), filename: "".to_owned(),
width: w as _, width: w as _,
height: h as _, height: h as _,

View File

@ -1145,8 +1145,8 @@ pub fn main_change_language(lang: String) {
send_to_cm(&crate::ipc::Data::Language(lang)); send_to_cm(&crate::ipc::Data::Language(lang));
} }
pub fn main_default_video_save_directory() -> String { pub fn main_video_save_directory(root: bool) -> String {
default_video_save_directory() video_save_directory(root)
} }
pub fn main_set_user_default_option(key: String, value: String) { pub fn main_set_user_default_option(key: String, value: String) {

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "跟随远程窗口焦点"), ("Follow remote window focus", "跟随远程窗口焦点"),
("default_proxy_tip", "默认代理协议及端口为 Socks5 和 1080"), ("default_proxy_tip", "默认代理协议及端口为 Socks5 和 1080"),
("no_audio_input_device_tip", "未找到音频输入设备"), ("no_audio_input_device_tip", "未找到音频输入设备"),
("Incoming", "被控"),
("Outgoing", "主控"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Sledovat zaměření vzdáleného okna"), ("Follow remote window focus", "Sledovat zaměření vzdáleného okna"),
("default_proxy_tip", "Výchozí protokol a port jsou Socks5 a 1080"), ("default_proxy_tip", "Výchozí protokol a port jsou Socks5 a 1080"),
("no_audio_input_device_tip", "Nebylo nalezeno žádné vstupní zvukové zařízení."), ("no_audio_input_device_tip", "Nebylo nalezeno žádné vstupní zvukové zařízení."),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Dem Fokus des entfernten Fensters folgen"), ("Follow remote window focus", "Dem Fokus des entfernten Fensters folgen"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Seguir ventana remota activa"), ("Follow remote window focus", "Seguir ventana remota activa"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Segui focus finestra remota"), ("Follow remote window focus", "Segui focus finestra remota"),
("default_proxy_tip", "Protocollo e porta predefiniti sono Socks5 e 1080"), ("default_proxy_tip", "Protocollo e porta predefiniti sono Socks5 e 1080"),
("no_audio_input_device_tip", "Nessun dispositivo input audio trovato."), ("no_audio_input_device_tip", "Nessun dispositivo input audio trovato."),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Sekot attālā loga fokusam"), ("Follow remote window focus", "Sekot attālā loga fokusam"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Volg de focus van het venster op afstand"), ("Follow remote window focus", "Volg de focus van het venster op afstand"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Podążaj za aktywnością zdalnych okien"), ("Follow remote window focus", "Podążaj za aktywnością zdalnych okien"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Следовать за фокусом удалённого окна"), ("Follow remote window focus", "Следовать за фокусом удалённого окна"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "Nasledovať vzdialené zameranie okna"), ("Follow remote window focus", "Nasledovať vzdialené zameranie okna"),
("default_proxy_tip", "Predvolený protokol a port sú Socks5 a 1080"), ("default_proxy_tip", "Predvolený protokol a port sú Socks5 a 1080"),
("no_audio_input_device_tip", "Nenašlo sa žiadne vstupné zvukové zariadenie."), ("no_audio_input_device_tip", "Nenašlo sa žiadne vstupné zvukové zariadenie."),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", "跟隨遠端視窗焦點"), ("Follow remote window focus", "跟隨遠端視窗焦點"),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -607,5 +607,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Follow remote window focus", ""), ("Follow remote window focus", ""),
("default_proxy_tip", ""), ("default_proxy_tip", ""),
("no_audio_input_device_tip", ""), ("no_audio_input_device_tip", ""),
("Incoming", ""),
("Outgoing", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -53,7 +53,7 @@ use scrap::{
codec::{Encoder, EncoderCfg, Quality}, codec::{Encoder, EncoderCfg, Quality},
record::{Recorder, RecorderContext}, record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId}, vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecFormat, CodecName, Display, Frame, TraitCapturer, CodecFormat, Display, Frame, TraitCapturer,
}; };
#[cfg(windows)] #[cfg(windows)]
use std::sync::Once; use std::sync::Once;
@ -752,6 +752,10 @@ fn get_recorder(
codec_format: &CodecFormat, codec_format: &CodecFormat,
record_incoming: bool, record_incoming: bool,
) -> Arc<Mutex<Option<Recorder>>> { ) -> Arc<Mutex<Option<Recorder>>> {
#[cfg(windows)]
let root = crate::platform::is_root();
#[cfg(not(windows))]
let root = false;
let recorder = if record_incoming { let recorder = if record_incoming {
use crate::hbbs_http::record_upload; use crate::hbbs_http::record_upload;
@ -765,7 +769,7 @@ fn get_recorder(
Recorder::new(RecorderContext { Recorder::new(RecorderContext {
server: true, server: true,
id: Config::get_id(), id: Config::get_id(),
default_dir: crate::ui_interface::default_video_save_directory(), dir: crate::ui_interface::video_save_directory(root),
filename: "".to_owned(), filename: "".to_owned(),
width, width,
height, height,

View File

@ -600,8 +600,8 @@ impl UI {
get_langs() get_langs()
} }
fn default_video_save_directory(&self) -> String { fn video_save_directory(&self, root: bool) -> String {
default_video_save_directory() video_save_directory(root)
} }
fn handle_relay_id(&self, id: String) -> String { fn handle_relay_id(&self, id: String) -> String {
@ -723,7 +723,7 @@ impl sciter::EventHandler for UI {
fn has_hwcodec(); fn has_hwcodec();
fn has_vram(); fn has_vram();
fn get_langs(); fn get_langs();
fn default_video_save_directory(); fn video_save_directory(bool);
fn handle_relay_id(String); fn handle_relay_id(String);
fn get_login_device_info(); fn get_login_device_info();
fn support_remove_wallpaper(); fn support_remove_wallpaper();

View File

@ -248,8 +248,9 @@ class Enhancements: Reactor.Component {
} else if (v.indexOf("allow-") == 0) { } else if (v.indexOf("allow-") == 0) {
handler.set_option(v, handler.get_option(v) == 'Y' ? '' : 'Y'); handler.set_option(v, handler.get_option(v) == 'Y' ? '' : 'Y');
} else if (v == 'screen-recording') { } else if (v == 'screen-recording') {
var dir = handler.get_option("video-save-directory"); var show_root_dir = is_win && handler.is_installed();
if (!dir) dir = handler.default_video_save_directory(); var user_dir = handler.video_save_directory(false);
var root_dir = show_root_dir ? handler.video_save_directory(true) : "";
var ts0 = handler.get_option("enable-record-session") == '' ? { checked: true } : {}; var ts0 = handler.get_option("enable-record-session") == '' ? { checked: true } : {};
var ts1 = handler.get_option("allow-auto-record-incoming") == 'Y' ? { checked: true } : {}; var ts1 = handler.get_option("allow-auto-record-incoming") == 'Y' ? { checked: true } : {};
msgbox("custom-recording", translate('Recording'), msgbox("custom-recording", translate('Recording'),
@ -257,7 +258,8 @@ class Enhancements: Reactor.Component {
<div><button|checkbox(enable_record_session) {ts0}>{translate('Enable recording session')}</button></div> <div><button|checkbox(enable_record_session) {ts0}>{translate('Enable recording session')}</button></div>
<div><button|checkbox(auto_record_incoming) {ts1}>{translate('Automatically record incoming sessions')}</button></div> <div><button|checkbox(auto_record_incoming) {ts1}>{translate('Automatically record incoming sessions')}</button></div>
<div> <div>
<div style="word-wrap:break-word"><span>{translate("Directory")}:&nbsp;&nbsp;</span><span #folderPath>{dir}</span></div> {show_root_dir ? <div style="word-wrap:break-word"><span>{translate("Incoming")}:&nbsp;&nbsp;</span><span>{root_dir}</span></div> : ""}
<div style="word-wrap:break-word"><span>{translate(show_root_dir ? "Outgoing" : "Directory")}:&nbsp;&nbsp;</span><span #folderPath>{user_dir}</span></div>
<div> <button #select_directory .link>{translate('Change')}</button> </div> <div> <button #select_directory .link>{translate('Change')}</button> </div>
</div> </div>
</div> </div>

View File

@ -778,7 +778,7 @@ pub fn get_langs() -> String {
} }
#[inline] #[inline]
pub fn default_video_save_directory() -> String { pub fn video_save_directory(root: bool) -> String {
let appname = crate::get_app_name(); let appname = crate::get_app_name();
// ui process can show it correctly Once vidoe process created it. // ui process can show it correctly Once vidoe process created it.
let try_create = |path: &std::path::Path| { let try_create = |path: &std::path::Path| {
@ -792,6 +792,20 @@ pub fn default_video_save_directory() -> String {
} }
}; };
if root {
// Currently, only installed windows run as root
#[cfg(windows)]
{
let drive = std::env::var("SystemDrive").unwrap_or("C:".to_owned());
let dir =
std::path::PathBuf::from(format!("{drive}\\ProgramData\\RustDesk\\recording",));
return dir.to_string_lossy().to_string();
}
}
let dir = Config::get_option("video-save-directory");
if !dir.is_empty() {
return dir;
}
#[cfg(any(target_os = "android", target_os = "ios"))] #[cfg(any(target_os = "android", target_os = "ios"))]
if let Ok(home) = config::APP_HOME_DIR.read() { if let Ok(home) = config::APP_HOME_DIR.read() {
let mut path = home.to_owned(); let mut path = home.to_owned();
@ -858,7 +872,7 @@ pub fn default_video_save_directory() -> String {
return parent.to_string_lossy().to_string(); return parent.to_string_lossy().to_string();
} }
} }
"".to_owned() Default::default()
} }
#[inline] #[inline]