Compare commits
5 commits
8c8c13167b
...
b257f03f65
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b257f03f65 | ||
|
|
24457ad6c9 | ||
|
|
85a004e263 | ||
|
|
9c25108356 | ||
|
|
16240609de |
50 changed files with 1647 additions and 200 deletions
|
|
@ -9,9 +9,9 @@ resolver = "2"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Abraham Tugalov (original)", "Bossiara13 (fork)"]
|
authors = ["Bossiara13"]
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
repository = "https://github.com/Priler/jarvis"
|
repository = "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-rust"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,112 @@ pub fn list_paths(commands: &[JCommandsList]) -> Vec<&Path> {
|
||||||
commands.iter().map(|x| x.path.as_path()).collect()
|
commands.iter().map(|x| x.path.as_path()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
fn resources_commands_dir() -> PathBuf {
|
||||||
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||||
|
.parent().unwrap()
|
||||||
|
.parent().unwrap()
|
||||||
|
.join("resources/commands")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_command_toml_parses() {
|
||||||
|
let cmds_dir = resources_commands_dir();
|
||||||
|
assert!(cmds_dir.is_dir(), "missing {}", cmds_dir.display());
|
||||||
|
|
||||||
|
let mut failures = Vec::new();
|
||||||
|
let mut packs_seen = 0;
|
||||||
|
|
||||||
|
for entry in fs::read_dir(&cmds_dir).expect("read_dir") {
|
||||||
|
let entry = entry.expect("entry");
|
||||||
|
let toml_file = entry.path().join("command.toml");
|
||||||
|
if !toml_file.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
packs_seen += 1;
|
||||||
|
let body = fs::read_to_string(&toml_file).expect("read");
|
||||||
|
if let Err(e) = toml::from_str::<JCommandsList>(&body) {
|
||||||
|
failures.push(format!("{}: {}", toml_file.display(), e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(packs_seen > 0, "no command packs found in {}", cmds_dir.display());
|
||||||
|
assert!(
|
||||||
|
failures.is_empty(),
|
||||||
|
"parse failures ({}):\n{}",
|
||||||
|
failures.len(),
|
||||||
|
failures.join("\n")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn lua_command_scripts_exist() {
|
||||||
|
let cmds_dir = resources_commands_dir();
|
||||||
|
let mut missing = Vec::new();
|
||||||
|
|
||||||
|
for entry in fs::read_dir(&cmds_dir).expect("read_dir") {
|
||||||
|
let entry = entry.expect("entry");
|
||||||
|
let pack_path = entry.path();
|
||||||
|
let toml_file = pack_path.join("command.toml");
|
||||||
|
if !toml_file.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let body = fs::read_to_string(&toml_file).expect("read");
|
||||||
|
let pack: JCommandsList = toml::from_str(&body).expect("parse");
|
||||||
|
for cmd in &pack.commands {
|
||||||
|
if cmd.cmd_type != "lua" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let script = if cmd.script.is_empty() {
|
||||||
|
"script.lua".to_string()
|
||||||
|
} else {
|
||||||
|
cmd.script.clone()
|
||||||
|
};
|
||||||
|
let script_path = pack_path.join(&script);
|
||||||
|
if !script_path.exists() {
|
||||||
|
missing.push(format!(
|
||||||
|
"{} -> {} (missing)",
|
||||||
|
cmd.id,
|
||||||
|
script_path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(missing.is_empty(), "missing Lua scripts:\n{}", missing.join("\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn every_command_has_phrases() {
|
||||||
|
let cmds_dir = resources_commands_dir();
|
||||||
|
let mut empty = Vec::new();
|
||||||
|
|
||||||
|
for entry in fs::read_dir(&cmds_dir).expect("read_dir") {
|
||||||
|
let toml_file = entry.expect("entry").path().join("command.toml");
|
||||||
|
if !toml_file.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let body = fs::read_to_string(&toml_file).expect("read");
|
||||||
|
let pack: JCommandsList = toml::from_str(&body).expect("parse");
|
||||||
|
for cmd in &pack.commands {
|
||||||
|
// structural commands (terminate, stop_chaining) may omit phrases
|
||||||
|
if cmd.cmd_type == "terminate" || cmd.cmd_type == "stop_chaining" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let total: usize = cmd.phrases.values().map(|v| v.len()).sum();
|
||||||
|
if total == 0 {
|
||||||
|
empty.push(cmd.id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(empty.is_empty(), "commands with no phrases: {:?}", empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "lua")]
|
#[cfg(feature = "lua")]
|
||||||
fn execute_lua_command(
|
fn execute_lua_command(
|
||||||
cmd_path: &PathBuf,
|
cmd_path: &PathBuf,
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,9 @@ pub const LOG_FILE_NAME: &str = "log.txt";
|
||||||
pub const APP_VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
|
pub const APP_VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
|
||||||
pub const AUTHOR_NAME: Option<&str> = option_env!("CARGO_PKG_AUTHORS");
|
pub const AUTHOR_NAME: Option<&str> = option_env!("CARGO_PKG_AUTHORS");
|
||||||
pub const REPOSITORY_LINK: Option<&str> = option_env!("CARGO_PKG_REPOSITORY");
|
pub const REPOSITORY_LINK: Option<&str> = option_env!("CARGO_PKG_REPOSITORY");
|
||||||
pub const TG_OFFICIAL_LINK: Option<&str> = Some("https://t.me/howdyho_official");
|
pub const UPSTREAM_REPOSITORY_LINK: &str = "https://github.com/Priler/jarvis";
|
||||||
pub const FEEDBACK_LINK: Option<&str> = Some("https://t.me/jarvis_feedback_bot");
|
pub const ISSUES_LINK: &str = "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-rust/issues";
|
||||||
pub const SUPPORT_BOOSTY_LINK: Option<&str> = Some("https://boosty.to/howdyho");
|
pub const PYTHON_FORK_LINK: &str = "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-py";
|
||||||
pub const SUPPORT_PATREON_LINK: Option<&str> = Some("https://www.patreon.com/c/priler");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Tray.
|
Tray.
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,9 @@ stats-not-selected = Not selected
|
||||||
stats-loading = Loading...
|
stats-loading = Loading...
|
||||||
|
|
||||||
# ### FOOTER
|
# ### FOOTER
|
||||||
footer-author = Project author
|
footer-github = Project repository
|
||||||
footer-telegram = Our Telegram channel
|
footer-issues = Report a bug
|
||||||
footer-github = Github repository
|
footer-fork-of = Fork of
|
||||||
footer-support = Support the project on
|
|
||||||
|
|
||||||
# ### SETTINGS
|
# ### SETTINGS
|
||||||
settings-title = Settings
|
settings-title = Settings
|
||||||
|
|
@ -84,8 +83,8 @@ settings-disabled = Disabled
|
||||||
# settings - beta notice
|
# settings - beta notice
|
||||||
settings-beta-title = BETA version!
|
settings-beta-title = BETA version!
|
||||||
settings-beta-desc = Some features may not work correctly.
|
settings-beta-desc = Some features may not work correctly.
|
||||||
settings-beta-feedback = Report all bugs to
|
settings-beta-feedback = Report bugs via
|
||||||
settings-beta-bot = our Telegram bot
|
settings-beta-bot = GitHub Issues
|
||||||
settings-open-logs = Open logs folder
|
settings-open-logs = Open logs folder
|
||||||
|
|
||||||
# settings - picovoice
|
# settings - picovoice
|
||||||
|
|
@ -112,10 +111,12 @@ settings-openai-not-supported = ChatGPT is not currently supported. It will be a
|
||||||
commands-title = Commands
|
commands-title = Commands
|
||||||
commands-search = Search commands...
|
commands-search = Search commands...
|
||||||
commands-count = { $count } commands
|
commands-count = { $count } commands
|
||||||
commands-wip-title = [404] This section is under development!
|
commands-wip-title = Section under development
|
||||||
commands-wip-desc = Here will be a list of commands + full-featured command editor.
|
commands-wip-desc = This will host the command editor and list of installed packs.
|
||||||
commands-wip-follow = Follow updates in
|
commands-wip-builder = For now, use the Python fork with the command builder —
|
||||||
commands-wip-channel = our Telegram channel
|
commands-wip-builder-link = open repository
|
||||||
|
commands-wip-or-fork = Or check the Rust repo and edit commands directly in
|
||||||
|
commands-wip-fork-link = resources/commands/
|
||||||
|
|
||||||
# ### ERRORS
|
# ### ERRORS
|
||||||
error-generic = An error occurred
|
error-generic = An error occurred
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,9 @@ stats-not-selected = Не выбран
|
||||||
stats-loading = Загрузка...
|
stats-loading = Загрузка...
|
||||||
|
|
||||||
# FOOTER
|
# FOOTER
|
||||||
footer-author = Автор проекта
|
footer-github = Репозиторий проекта
|
||||||
footer-telegram = Наш телеграм канал
|
footer-issues = Сообщить о баге
|
||||||
footer-github = Github репозиторий проекта
|
footer-fork-of = Форк
|
||||||
footer-support = Поддержать проект на
|
|
||||||
|
|
||||||
# SETTINGS
|
# SETTINGS
|
||||||
settings-title = Настройки
|
settings-title = Настройки
|
||||||
|
|
@ -84,8 +83,8 @@ settings-disabled = Отключено
|
||||||
# settings - beta notice
|
# settings - beta notice
|
||||||
settings-beta-title = БЕТА версия!
|
settings-beta-title = БЕТА версия!
|
||||||
settings-beta-desc = Часть функций может работать некорректно.
|
settings-beta-desc = Часть функций может работать некорректно.
|
||||||
settings-beta-feedback = Сообщайте обо всех найденных багах в
|
settings-beta-feedback = Сообщайте обо всех найденных багах через
|
||||||
settings-beta-bot = наш телеграм бот
|
settings-beta-bot = GitHub Issues
|
||||||
settings-open-logs = Открыть папку с логами
|
settings-open-logs = Открыть папку с логами
|
||||||
|
|
||||||
# settings - picovoice
|
# settings - picovoice
|
||||||
|
|
@ -112,10 +111,12 @@ settings-openai-not-supported = В данный момент ChatGPT не под
|
||||||
commands-title = Команды
|
commands-title = Команды
|
||||||
commands-search = Поиск команд...
|
commands-search = Поиск команд...
|
||||||
commands-count = { $count } команд
|
commands-count = { $count } команд
|
||||||
commands-wip-title = [404] Этот раздел еще находится в разработке!
|
commands-wip-title = Раздел в разработке
|
||||||
commands-wip-desc = Тут будет список команд + полноценный редактор команд.
|
commands-wip-desc = Здесь будет редактор команд и список установленных пакетов.
|
||||||
commands-wip-follow = Следите за обновлениями в
|
commands-wip-builder = Пока что используй Python-форк с конструктором команд —
|
||||||
commands-wip-channel = нашем телеграм канале
|
commands-wip-builder-link = открыть репозиторий
|
||||||
|
commands-wip-or-fork = Или загляни в Rust-репозиторий и правь команды напрямую в
|
||||||
|
commands-wip-fork-link = resources/commands/
|
||||||
|
|
||||||
# ERRORS
|
# ERRORS
|
||||||
error-generic = Произошла ошибка
|
error-generic = Произошла ошибка
|
||||||
|
|
|
||||||
|
|
@ -42,10 +42,9 @@ stats-not-selected = Не вибрано
|
||||||
stats-loading = Завантаження...
|
stats-loading = Завантаження...
|
||||||
|
|
||||||
# ### FOOTER
|
# ### FOOTER
|
||||||
footer-author = Автор проєкту
|
footer-github = Репозиторій проєкту
|
||||||
footer-telegram = Наш телеграм канал
|
footer-issues = Повідомити про баг
|
||||||
footer-github = Github репозиторій проєкту
|
footer-fork-of = Форк
|
||||||
footer-support = Підтримати проєкт на
|
|
||||||
|
|
||||||
# ### SETTINGS
|
# ### SETTINGS
|
||||||
settings-title = Налаштування
|
settings-title = Налаштування
|
||||||
|
|
@ -84,8 +83,8 @@ settings-disabled = Вимкнено
|
||||||
# settings - beta notice
|
# settings - beta notice
|
||||||
settings-beta-title = БЕТА версія!
|
settings-beta-title = БЕТА версія!
|
||||||
settings-beta-desc = Частина функцій може працювати некоректно.
|
settings-beta-desc = Частина функцій може працювати некоректно.
|
||||||
settings-beta-feedback = Повідомляйте про всі знайдені баги в
|
settings-beta-feedback = Повідомляйте про знайдені баги через
|
||||||
settings-beta-bot = наш телеграм бот
|
settings-beta-bot = GitHub Issues
|
||||||
settings-open-logs = Відкрити папку з логами
|
settings-open-logs = Відкрити папку з логами
|
||||||
|
|
||||||
# settings - picovoice
|
# settings - picovoice
|
||||||
|
|
@ -112,10 +111,12 @@ settings-openai-not-supported = Наразі ChatGPT не підтримуєть
|
||||||
commands-title = Команди
|
commands-title = Команди
|
||||||
commands-search = Пошук команд...
|
commands-search = Пошук команд...
|
||||||
commands-count = { $count } команд
|
commands-count = { $count } команд
|
||||||
commands-wip-title = [404] Цей розділ ще в розробці!
|
commands-wip-title = Розділ у розробці
|
||||||
commands-wip-desc = Тут буде список команд + повноцінний редактор команд.
|
commands-wip-desc = Тут буде редактор команд та список встановлених пакетів.
|
||||||
commands-wip-follow = Слідкуйте за оновленнями в
|
commands-wip-builder = Поки що користуйся Python-форком з конструктором команд —
|
||||||
commands-wip-channel = нашому телеграм каналі
|
commands-wip-builder-link = відкрити репозиторій
|
||||||
|
commands-wip-or-fork = Або зазирни в Rust-репозиторій і правь команди безпосередньо в
|
||||||
|
commands-wip-fork-link = resources/commands/
|
||||||
|
|
||||||
# ### ERRORS
|
# ### ERRORS
|
||||||
error-generic = Сталася помилка
|
error-generic = Сталася помилка
|
||||||
|
|
|
||||||
|
|
@ -60,10 +60,9 @@ fn main() {
|
||||||
tauri_commands::get_app_version,
|
tauri_commands::get_app_version,
|
||||||
tauri_commands::get_author_name,
|
tauri_commands::get_author_name,
|
||||||
tauri_commands::get_repository_link,
|
tauri_commands::get_repository_link,
|
||||||
tauri_commands::get_tg_official_link,
|
tauri_commands::get_upstream_link,
|
||||||
tauri_commands::get_boosty_link,
|
tauri_commands::get_issues_link,
|
||||||
tauri_commands::get_patreon_link,
|
tauri_commands::get_python_fork_link,
|
||||||
tauri_commands::get_feedback_link,
|
|
||||||
|
|
||||||
// fs
|
// fs
|
||||||
tauri_commands::get_log_file_path,
|
tauri_commands::get_log_file_path,
|
||||||
|
|
|
||||||
|
|
@ -1,68 +1,33 @@
|
||||||
use jarvis_core::{config, APP_LOG_DIR};
|
use jarvis_core::{config, APP_LOG_DIR};
|
||||||
|
|
||||||
// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
|
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_app_version() -> String {
|
pub fn get_app_version() -> String {
|
||||||
if let Some(res) = config::APP_VERSION {
|
config::APP_VERSION.unwrap_or("error").to_string()
|
||||||
res.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_author_name() -> String {
|
pub fn get_author_name() -> String {
|
||||||
if let Some(res) = config::AUTHOR_NAME {
|
config::AUTHOR_NAME.unwrap_or("error").to_string()
|
||||||
res.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_repository_link() -> String {
|
pub fn get_repository_link() -> String {
|
||||||
if let Some(res) = config::REPOSITORY_LINK {
|
config::REPOSITORY_LINK.unwrap_or("error").to_string()
|
||||||
res.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_tg_official_link() -> String {
|
pub fn get_upstream_link() -> String {
|
||||||
if let Some(ver) = config::TG_OFFICIAL_LINK {
|
config::UPSTREAM_REPOSITORY_LINK.to_string()
|
||||||
ver.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_boosty_link() -> String {
|
pub fn get_issues_link() -> String {
|
||||||
if let Some(ver) = config::SUPPORT_BOOSTY_LINK {
|
config::ISSUES_LINK.to_string()
|
||||||
ver.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_patreon_link() -> String {
|
pub fn get_python_fork_link() -> String {
|
||||||
if let Some(ver) = config::SUPPORT_PATREON_LINK {
|
config::PYTHON_FORK_LINK.to_string()
|
||||||
ver.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn get_feedback_link() -> String {
|
|
||||||
if let Some(res) = config::FEEDBACK_LINK {
|
|
||||||
res.to_string()
|
|
||||||
} else {
|
|
||||||
String::from("error")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
|
@ -70,4 +35,4 @@ pub fn get_log_file_path() -> String {
|
||||||
APP_LOG_DIR.get()
|
APP_LOG_DIR.get()
|
||||||
.map(|p| p.display().to_string())
|
.map(|p| p.display().to_string())
|
||||||
.unwrap_or_else(|| "unknown".to_string())
|
.unwrap_or_else(|| "unknown".to_string())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,39 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from "svelte"
|
import { appInfo, translations, translate } from "@/stores"
|
||||||
import { invoke } from "@tauri-apps/api/core"
|
|
||||||
import { appInfo, currentLanguage, translations, translate } from "@/stores"
|
|
||||||
|
|
||||||
$: t = (key: string) => translate($translations, key)
|
$: t = (key: string) => translate($translations, key)
|
||||||
|
|
||||||
let authorName = ""
|
|
||||||
let tgLink = ""
|
|
||||||
let repoLink = ""
|
let repoLink = ""
|
||||||
let boostyLink = ""
|
let upstreamLink = ""
|
||||||
let patreonLink = ""
|
let issuesLink = ""
|
||||||
|
|
||||||
const currentYear = new Date().getFullYear()
|
const currentYear = new Date().getFullYear()
|
||||||
|
|
||||||
appInfo.subscribe(info => {
|
appInfo.subscribe(info => {
|
||||||
tgLink = info.tgOfficialLink
|
|
||||||
repoLink = info.repositoryLink
|
repoLink = info.repositoryLink
|
||||||
boostyLink = info.boostySupportLink
|
upstreamLink = info.upstreamLink
|
||||||
patreonLink = info.patreonSupportLink
|
issuesLink = info.issuesLink
|
||||||
})
|
|
||||||
|
|
||||||
onMount(async () => {
|
|
||||||
try {
|
|
||||||
authorName = await invoke<string>("get_author_name")
|
|
||||||
} catch (err) {
|
|
||||||
console.error("failed to get author name:", err)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<footer id="footer">
|
<footer id="footer">
|
||||||
<p>© {currentYear}. {t('footer-author')}: <b>{authorName}</b></p>
|
<p>© {currentYear} J.A.R.V.I.S.</p>
|
||||||
<p class="links">
|
<p class="links">
|
||||||
{#if $currentLanguage === "ru" || $currentLanguage === "ua"}
|
<a href={repoLink} target="_blank" rel="noopener noreferrer">
|
||||||
<a href={tgLink} target="_blank" class="telegram-link">
|
|
||||||
<img src="/media/icons/telegram.webp" alt="Telegram" width="18px" />
|
|
||||||
<span>{t('footer-telegram')}</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
{/if}
|
|
||||||
<a href={repoLink} target="_blank">
|
|
||||||
<img src="/media/icons/github-logo.png" alt="GitHub" width="18px" />
|
<img src="/media/icons/github-logo.png" alt="GitHub" width="18px" />
|
||||||
<span>{t('footer-github')}</span>
|
<span>{t('footer-github')}</span>
|
||||||
</a>
|
</a>
|
||||||
|
·
|
||||||
|
<a href={issuesLink} target="_blank" rel="noopener noreferrer">
|
||||||
|
<span>{t('footer-issues')}</span>
|
||||||
|
</a>
|
||||||
</p>
|
</p>
|
||||||
<p class="links last">
|
<p class="links last">
|
||||||
{#if $currentLanguage === "ru"}
|
<small>
|
||||||
{t('footer-support')} <a href={boostyLink} target="_blank" class="telegram-link">
|
{t('footer-fork-of')}
|
||||||
<img src="/media/icons/boosty.webp" alt="Boosty" width="18px" />
|
<a href={upstreamLink} target="_blank" rel="noopener noreferrer">Priler/jarvis</a>
|
||||||
<span>Boosty</span>
|
· CC BY-NC-SA 4.0
|
||||||
</a>.
|
</small>
|
||||||
{/if}
|
|
||||||
{#if $currentLanguage === "ua" || $currentLanguage === "en"}
|
|
||||||
{t('footer-support')} <a href={patreonLink} target="_blank" class="telegram-link">
|
|
||||||
<img src="/media/icons/patreon.png" alt="Patreon" width="18px" />
|
|
||||||
<span>Patreon</span>
|
|
||||||
</a>.
|
|
||||||
{/if}
|
|
||||||
</p>
|
</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|
@ -79,15 +56,17 @@
|
||||||
|
|
||||||
&.last {
|
&.last {
|
||||||
margin-top: -5px;
|
margin-top: -5px;
|
||||||
|
color: #8a8d90;
|
||||||
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: #555759!important;
|
color: #555759 !important;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: 0.3s;
|
transition: 0.3s;
|
||||||
|
|
||||||
& > span {
|
& > span {
|
||||||
color: #185876;
|
color: #185876;
|
||||||
border-bottom: 1px solid #185876;
|
border-bottom: 1px solid #185876;
|
||||||
|
|
@ -101,7 +80,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: #777a7d!important;
|
color: #777a7d !important;
|
||||||
|
|
||||||
& > span {
|
& > span {
|
||||||
color: #2A9CD0;
|
color: #2A9CD0;
|
||||||
|
|
@ -111,30 +90,6 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.telegram-link {
|
|
||||||
color: #185876;
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #2A9CD0;
|
|
||||||
// background: url(/media/images/bg/bg24.gif);
|
|
||||||
// background-repeat: no-repeat;
|
|
||||||
// background-size: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.special-link {
|
|
||||||
color: #941d92;
|
|
||||||
display: inline-block;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #FF07FC;
|
|
||||||
background: url(/media/images/bg/bg24.gif);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-size: contain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,11 @@
|
||||||
|
|
||||||
$: t = (key: string) => translate($translations, key)
|
$: t = (key: string) => translate($translations, key)
|
||||||
|
|
||||||
let tgLink = ""
|
let pythonForkLink = ""
|
||||||
|
let repoLink = ""
|
||||||
appInfo.subscribe(info => {
|
appInfo.subscribe(info => {
|
||||||
tgLink = info.tgOfficialLink
|
pythonForkLink = info.pythonForkLink
|
||||||
|
repoLink = info.repositoryLink
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -23,19 +25,11 @@
|
||||||
withCloseButton={false}
|
withCloseButton={false}
|
||||||
>
|
>
|
||||||
{t('commands-wip-desc')}<br />
|
{t('commands-wip-desc')}<br />
|
||||||
{t('commands-wip-follow')} <a href={tgLink} target="_blank">{t('commands-wip-channel')}</a>!
|
{t('commands-wip-builder')}
|
||||||
|
<a href={pythonForkLink} target="_blank" rel="noopener noreferrer">{t('commands-wip-builder-link')}</a>.
|
||||||
|
{t('commands-wip-or-fork')}
|
||||||
|
<a href={repoLink} target="_blank" rel="noopener noreferrer">{t('commands-wip-fork-link')}</a>.
|
||||||
</Notification>
|
</Notification>
|
||||||
|
|
||||||
<div class="placeholder-image">
|
|
||||||
<img src="/media/images/tenor.gif" alt="bruh" width="320px" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<HDivider />
|
<HDivider />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
<style>
|
|
||||||
.placeholder-image {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 25px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -90,10 +90,10 @@
|
||||||
voiceVal = value
|
voiceVal = value
|
||||||
})
|
})
|
||||||
|
|
||||||
let feedbackLink = ""
|
let issuesLink = ""
|
||||||
let logFilePath = ""
|
let logFilePath = ""
|
||||||
appInfo.subscribe(info => {
|
appInfo.subscribe(info => {
|
||||||
feedbackLink = info.feedbackLink
|
issuesLink = info.issuesLink
|
||||||
logFilePath = info.logFilePath
|
logFilePath = info.logFilePath
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -230,7 +230,7 @@
|
||||||
withCloseButton={false}
|
withCloseButton={false}
|
||||||
>
|
>
|
||||||
{t('settings-beta-desc')}<br />
|
{t('settings-beta-desc')}<br />
|
||||||
{t('settings-beta-feedback')} <a href={feedbackLink} target="_blank">{t('settings-beta-bot')}</a>.
|
{t('settings-beta-feedback')} <a href={issuesLink} target="_blank" rel="noopener noreferrer">{t('settings-beta-bot')}</a>.
|
||||||
<Space h="sm" />
|
<Space h="sm" />
|
||||||
<Button
|
<Button
|
||||||
color="gray"
|
color="gray"
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,21 @@ export const jarvisCpuUsage = writable(0)
|
||||||
export const assistantVoice = writable("")
|
export const assistantVoice = writable("")
|
||||||
|
|
||||||
// ### APP INFO
|
// ### APP INFO
|
||||||
|
// Hardcoded fallbacks so the UI keeps working when the Rust side has not
|
||||||
|
// been rebuilt yet (the new get_upstream_link / get_issues_link / get_python_fork_link
|
||||||
|
// Tauri commands only exist after the next cargo build).
|
||||||
|
const BRANDING_FALLBACK = {
|
||||||
|
repositoryLink: "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-rust",
|
||||||
|
upstreamLink: "https://github.com/Priler/jarvis",
|
||||||
|
issuesLink: "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-rust/issues",
|
||||||
|
pythonForkLink: "https://github.com/DmitryBykov-ISPO/J.A.R.V.I.S-py",
|
||||||
|
}
|
||||||
|
|
||||||
export const appInfo = writable({
|
export const appInfo = writable({
|
||||||
tgOfficialLink: "",
|
repositoryLink: BRANDING_FALLBACK.repositoryLink,
|
||||||
feedbackLink: "",
|
upstreamLink: BRANDING_FALLBACK.upstreamLink,
|
||||||
repositoryLink: "",
|
issuesLink: BRANDING_FALLBACK.issuesLink,
|
||||||
boostySupportLink: "",
|
pythonForkLink: BRANDING_FALLBACK.pythonForkLink,
|
||||||
patreonSupportLink: "",
|
|
||||||
logFilePath: ""
|
logFilePath: ""
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -59,27 +68,38 @@ export async function loadVoiceSetting() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadAppInfo() {
|
export async function loadAppInfo() {
|
||||||
try {
|
const fetchOr = async (name: string, fallback: string): Promise<string> => {
|
||||||
const [tg, feedback, repo, boosty, patreon, logPath] = await Promise.all([
|
try {
|
||||||
invoke<string>("get_tg_official_link"),
|
const v = await invoke<string>(name)
|
||||||
invoke<string>("get_feedback_link"),
|
return v && v !== "error" ? v : fallback
|
||||||
invoke<string>("get_repository_link"),
|
} catch {
|
||||||
invoke<string>("get_boosty_link"),
|
return fallback
|
||||||
invoke<string>("get_patreon_link"),
|
}
|
||||||
invoke<string>("get_log_file_path")
|
|
||||||
])
|
|
||||||
|
|
||||||
appInfo.set({
|
|
||||||
tgOfficialLink: tg,
|
|
||||||
feedbackLink: feedback,
|
|
||||||
repositoryLink: repo,
|
|
||||||
boostySupportLink: boosty,
|
|
||||||
patreonSupportLink: patreon,
|
|
||||||
logFilePath: logPath
|
|
||||||
})
|
|
||||||
} catch (err) {
|
|
||||||
console.error("failed to load app info:", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The old binary's get_repository_link returns Priler's upstream — override
|
||||||
|
// so we never display the upstream repo as if it were the current fork.
|
||||||
|
const fetchRepoOr = async (fallback: string): Promise<string> => {
|
||||||
|
const v = await fetchOr("get_repository_link", fallback)
|
||||||
|
if (/priler\/jarvis/i.test(v)) return fallback
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
const [repo, upstream, issues, pythonFork, logPath] = await Promise.all([
|
||||||
|
fetchRepoOr(BRANDING_FALLBACK.repositoryLink),
|
||||||
|
fetchOr("get_upstream_link", BRANDING_FALLBACK.upstreamLink),
|
||||||
|
fetchOr("get_issues_link", BRANDING_FALLBACK.issuesLink),
|
||||||
|
fetchOr("get_python_fork_link", BRANDING_FALLBACK.pythonForkLink),
|
||||||
|
fetchOr("get_log_file_path", "")
|
||||||
|
])
|
||||||
|
|
||||||
|
appInfo.set({
|
||||||
|
repositoryLink: repo,
|
||||||
|
upstreamLink: upstream,
|
||||||
|
issuesLink: issues,
|
||||||
|
pythonForkLink: pythonFork,
|
||||||
|
logFilePath: logPath
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateJarvisStats() {
|
export async function updateJarvisStats() {
|
||||||
|
|
@ -98,7 +118,7 @@ let statsInterval: ReturnType<typeof setInterval> | null = null
|
||||||
|
|
||||||
export function startStatsPolling(intervalMs = 5000) {
|
export function startStatsPolling(intervalMs = 5000) {
|
||||||
if (statsInterval) return // already running
|
if (statsInterval) return // already running
|
||||||
|
|
||||||
updateJarvisStats()
|
updateJarvisStats()
|
||||||
statsInterval = setInterval(updateJarvisStats, intervalMs)
|
statsInterval = setInterval(updateJarvisStats, intervalMs)
|
||||||
}
|
}
|
||||||
|
|
@ -108,4 +128,4 @@ export function stopStatsPolling() {
|
||||||
clearInterval(statsInterval)
|
clearInterval(statsInterval)
|
||||||
statsInterval = null
|
statsInterval = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
230
resources/commands/apps/command.toml
Normal file
230
resources/commands/apps/command.toml
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "open_browser"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_browser.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой браузер",
|
||||||
|
"запусти браузер",
|
||||||
|
"открой хром",
|
||||||
|
"запусти хром",
|
||||||
|
"включи браузер",
|
||||||
|
"браузер открой",
|
||||||
|
"нужен браузер",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open browser",
|
||||||
|
"launch browser",
|
||||||
|
"open chrome",
|
||||||
|
"launch chrome",
|
||||||
|
"start browser",
|
||||||
|
"i need browser",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий браузер",
|
||||||
|
"запусти браузер",
|
||||||
|
"відкрий хром",
|
||||||
|
"запусти хром",
|
||||||
|
"увімкни браузер",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_notepad"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_notepad.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой блокнот",
|
||||||
|
"запусти блокнот",
|
||||||
|
"открой нотепад",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open notepad",
|
||||||
|
"launch notepad",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий блокнот",
|
||||||
|
"запусти блокнот",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_calculator"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_calculator.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой калькулятор",
|
||||||
|
"запусти калькулятор",
|
||||||
|
"нужен калькулятор",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open calculator",
|
||||||
|
"launch calculator",
|
||||||
|
"calculator please",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий калькулятор",
|
||||||
|
"запусти калькулятор",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_explorer"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_explorer.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой проводник",
|
||||||
|
"открой папку",
|
||||||
|
"запусти проводник",
|
||||||
|
"открой файлы",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open explorer",
|
||||||
|
"open file explorer",
|
||||||
|
"open files",
|
||||||
|
"open folder",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий провідник",
|
||||||
|
"відкрий папку",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_terminal"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_terminal.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой терминал",
|
||||||
|
"запусти терминал",
|
||||||
|
"открой консоль",
|
||||||
|
"запусти консоль",
|
||||||
|
"открой повершелл",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open terminal",
|
||||||
|
"open powershell",
|
||||||
|
"open console",
|
||||||
|
"launch terminal",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий термінал",
|
||||||
|
"відкрий консоль",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_settings"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_settings.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой настройки",
|
||||||
|
"открой параметры",
|
||||||
|
"запусти настройки",
|
||||||
|
"открой настройки виндоус",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open settings",
|
||||||
|
"launch settings",
|
||||||
|
"windows settings",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий налаштування",
|
||||||
|
"відкрий параметри",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "open_task_manager"
|
||||||
|
type = "lua"
|
||||||
|
script = "open_task_manager.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"открой диспетчер задач",
|
||||||
|
"запусти диспетчер задач",
|
||||||
|
"диспетчер задач",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"open task manager",
|
||||||
|
"launch task manager",
|
||||||
|
"task manager",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"відкрий диспетчер задач",
|
||||||
|
"диспетчер задач",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "lock_screen"
|
||||||
|
type = "lua"
|
||||||
|
script = "lock_screen.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"заблокируй компьютер",
|
||||||
|
"заблокируй экран",
|
||||||
|
"блокировка экрана",
|
||||||
|
"залочь",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"lock screen",
|
||||||
|
"lock the computer",
|
||||||
|
"lock pc",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"заблокуй комп'ютер",
|
||||||
|
"заблокуй екран",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "screenshot"
|
||||||
|
type = "lua"
|
||||||
|
script = "screenshot.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"сделай скриншот",
|
||||||
|
"скриншот",
|
||||||
|
"сними экран",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"take screenshot",
|
||||||
|
"screenshot",
|
||||||
|
"capture screen",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"зроби скріншот",
|
||||||
|
"знімок екрана",
|
||||||
|
]
|
||||||
8
resources/commands/apps/lock_screen.lua
Normal file
8
resources/commands/apps/lock_screen.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("rundll32.exe user32.dll,LockWorkStation")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "lock screen failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
9
resources/commands/apps/open_browser.lua
Normal file
9
resources/commands/apps/open_browser.lua
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
local cmd = "start \"\" \"https://www.google.com\""
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open browser failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
8
resources/commands/apps/open_calculator.lua
Normal file
8
resources/commands/apps/open_calculator.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" calc.exe")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open calculator failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
8
resources/commands/apps/open_explorer.lua
Normal file
8
resources/commands/apps/open_explorer.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" explorer.exe")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open explorer failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
8
resources/commands/apps/open_notepad.lua
Normal file
8
resources/commands/apps/open_notepad.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" notepad.exe")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open notepad failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
8
resources/commands/apps/open_settings.lua
Normal file
8
resources/commands/apps/open_settings.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" ms-settings:")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open settings failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
8
resources/commands/apps/open_task_manager.lua
Normal file
8
resources/commands/apps/open_task_manager.lua
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" taskmgr.exe")
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open task manager failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/apps/open_terminal.lua
Normal file
13
resources/commands/apps/open_terminal.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local res = jarvis.system.exec("start \"\" wt.exe")
|
||||||
|
if not res.success then
|
||||||
|
jarvis.log("warn", "wt.exe not found, falling back to powershell")
|
||||||
|
res = jarvis.system.exec("start \"\" powershell.exe")
|
||||||
|
end
|
||||||
|
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "open terminal failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
24
resources/commands/apps/screenshot.lua
Normal file
24
resources/commands/apps/screenshot.lua
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
local ts = jarvis.context.time.year .. jarvis.context.time.month .. jarvis.context.time.day
|
||||||
|
.. "_" .. jarvis.context.time.hour .. jarvis.context.time.minute .. jarvis.context.time.second
|
||||||
|
|
||||||
|
local userprofile = jarvis.system.env("USERPROFILE") or "C:\\Users\\Public"
|
||||||
|
local target = userprofile .. "\\Pictures\\jarvis_screenshot_" .. ts .. ".png"
|
||||||
|
|
||||||
|
local ps = string.format(
|
||||||
|
[[Add-Type -AssemblyName System.Windows.Forms,System.Drawing; $b=[System.Windows.Forms.Screen]::PrimaryScreen.Bounds; $bmp=New-Object Drawing.Bitmap $b.Width,$b.Height; $g=[Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($b.Location,[Drawing.Point]::Empty,$b.Size); $bmp.Save('%s'); $g.Dispose(); $bmp.Dispose()]],
|
||||||
|
target:gsub("\\", "\\\\")
|
||||||
|
)
|
||||||
|
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -Command "%s"', ps:gsub('"', '\\"'))
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
|
||||||
|
if res.success then
|
||||||
|
jarvis.log("info", "screenshot saved to " .. target)
|
||||||
|
jarvis.system.notify("Скриншот", target)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "screenshot failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
26
resources/commands/file_search/command.toml
Normal file
26
resources/commands/file_search/command.toml
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "file_search"
|
||||||
|
type = "lua"
|
||||||
|
script = "search.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 15000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"найди файл",
|
||||||
|
"поиск файла",
|
||||||
|
"ищи файл",
|
||||||
|
"где файл",
|
||||||
|
"найди документ",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"find file",
|
||||||
|
"search file",
|
||||||
|
"where is file",
|
||||||
|
"locate file",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"знайди файл",
|
||||||
|
"пошук файлу",
|
||||||
|
"де файл",
|
||||||
|
]
|
||||||
78
resources/commands/file_search/search.lua
Normal file
78
resources/commands/file_search/search.lua
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
local lang = jarvis.context.language
|
||||||
|
local phrase = (jarvis.context.phrase or ""):lower()
|
||||||
|
|
||||||
|
local triggers = {
|
||||||
|
"найди документ", "найди файл", "поиск файла", "ищи файл", "где файл",
|
||||||
|
"find file", "search file", "where is file", "locate file",
|
||||||
|
"знайди файл", "пошук файлу", "де файл",
|
||||||
|
}
|
||||||
|
|
||||||
|
local query = phrase
|
||||||
|
for _, t in ipairs(triggers) do
|
||||||
|
local start, finish = string.find(query, t, 1, true)
|
||||||
|
if start == 1 then
|
||||||
|
query = query:sub(finish + 1)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
query = query:gsub("^%s+", ""):gsub("%s+$", "")
|
||||||
|
|
||||||
|
if query == "" then
|
||||||
|
jarvis.log("warn", "file_search: empty query (phrase=" .. phrase .. ")")
|
||||||
|
jarvis.system.notify(
|
||||||
|
lang == "ru" and "Поиск файлов" or "File search",
|
||||||
|
lang == "ru" and "Что искать?" or "What to search for?"
|
||||||
|
)
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
return { chain = false }
|
||||||
|
end
|
||||||
|
|
||||||
|
local userprofile = jarvis.system.env("USERPROFILE") or "C:\\Users\\Public"
|
||||||
|
local roots = {
|
||||||
|
userprofile .. "\\Desktop",
|
||||||
|
userprofile .. "\\Documents",
|
||||||
|
userprofile .. "\\Downloads",
|
||||||
|
}
|
||||||
|
|
||||||
|
local escaped = query:gsub("'", "''")
|
||||||
|
local roots_arg = "'" .. table.concat(roots, "','") .. "'"
|
||||||
|
local ps = string.format(
|
||||||
|
[[$ErrorActionPreference='SilentlyContinue'; $r=@(%s); $q='*%s*'; $hits=Get-ChildItem -Path $r -Filter $q -Recurse -Depth 3 -File | Select-Object -First 5; foreach($h in $hits){ Write-Output $h.FullName }]],
|
||||||
|
roots_arg, escaped
|
||||||
|
)
|
||||||
|
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -Command "%s"', ps:gsub('"', '\\"'))
|
||||||
|
jarvis.log("info", "file_search query='" .. query .. "'")
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
|
||||||
|
if not res.success then
|
||||||
|
jarvis.log("error", "file_search exec failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
return { chain = false }
|
||||||
|
end
|
||||||
|
|
||||||
|
local stdout = res.stdout or ""
|
||||||
|
local lines = {}
|
||||||
|
for line in stdout:gmatch("[^\r\n]+") do
|
||||||
|
if line ~= "" then table.insert(lines, line) end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #lines == 0 then
|
||||||
|
jarvis.system.notify(
|
||||||
|
lang == "ru" and "Поиск файлов" or "File search",
|
||||||
|
(lang == "ru" and "Не найдено: " or "Not found: ") .. query
|
||||||
|
)
|
||||||
|
jarvis.audio.play_not_found()
|
||||||
|
else
|
||||||
|
local first = lines[1]
|
||||||
|
local count = #lines
|
||||||
|
local title = lang == "ru" and "Найдено файлов: " or "Files found: "
|
||||||
|
jarvis.system.notify(title .. count, first)
|
||||||
|
|
||||||
|
jarvis.log("info", "file_search opening: " .. first)
|
||||||
|
jarvis.system.exec(string.format('explorer.exe /select,"%s"', first))
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
20
resources/commands/media/_media_helper.ps1
Normal file
20
resources/commands/media/_media_helper.ps1
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateSet("play_pause","next","prev","stop")]
|
||||||
|
[string]$Action
|
||||||
|
)
|
||||||
|
|
||||||
|
Add-Type -Name MediaKey -Namespace Win32 -MemberDefinition @'
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, System.UIntPtr dwExtraInfo);
|
||||||
|
'@
|
||||||
|
|
||||||
|
$vk = switch ($Action) {
|
||||||
|
"play_pause" { 0xB3 }
|
||||||
|
"next" { 0xB0 }
|
||||||
|
"prev" { 0xB1 }
|
||||||
|
"stop" { 0xB2 }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Win32.MediaKey]::keybd_event($vk, 0, 0, [UIntPtr]::Zero)
|
||||||
|
[Win32.MediaKey]::keybd_event($vk, 0, 2, [UIntPtr]::Zero)
|
||||||
103
resources/commands/media/command.toml
Normal file
103
resources/commands/media/command.toml
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "media_play_pause"
|
||||||
|
type = "lua"
|
||||||
|
script = "play_pause.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"пауза",
|
||||||
|
"поставь на паузу",
|
||||||
|
"продолжи",
|
||||||
|
"включи музыку",
|
||||||
|
"запусти музыку",
|
||||||
|
"плей",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"pause",
|
||||||
|
"play",
|
||||||
|
"resume",
|
||||||
|
"play music",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"пауза",
|
||||||
|
"продовж",
|
||||||
|
"включи музику",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "media_next"
|
||||||
|
type = "lua"
|
||||||
|
script = "next_track.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"следующий трек",
|
||||||
|
"следующая песня",
|
||||||
|
"переключи трек",
|
||||||
|
"следующая",
|
||||||
|
"дальше",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"next track",
|
||||||
|
"next song",
|
||||||
|
"skip",
|
||||||
|
"next",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"наступний трек",
|
||||||
|
"наступна пісня",
|
||||||
|
"далі",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "media_prev"
|
||||||
|
type = "lua"
|
||||||
|
script = "prev_track.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"предыдущий трек",
|
||||||
|
"предыдущая песня",
|
||||||
|
"верни песню",
|
||||||
|
"назад",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"previous track",
|
||||||
|
"previous song",
|
||||||
|
"back",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"попередній трек",
|
||||||
|
"назад",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "media_stop"
|
||||||
|
type = "lua"
|
||||||
|
script = "stop_media.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"стоп музыка",
|
||||||
|
"останови музыку",
|
||||||
|
"выключи музыку",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"stop music",
|
||||||
|
"stop playback",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"стоп музика",
|
||||||
|
"вимкни музику",
|
||||||
|
]
|
||||||
13
resources/commands/media/next_track.lua
Normal file
13
resources/commands/media/next_track.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_media_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action next',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "media next failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/media/play_pause.lua
Normal file
13
resources/commands/media/play_pause.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_media_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action play_pause',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "play/pause failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/media/prev_track.lua
Normal file
13
resources/commands/media/prev_track.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_media_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action prev',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "media prev failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/media/stop_media.lua
Normal file
13
resources/commands/media/stop_media.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_media_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action stop',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "media stop failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
195
resources/commands/output_device/_audio_devices.ps1
Normal file
195
resources/commands/output_device/_audio_devices.ps1
Normal file
|
|
@ -0,0 +1,195 @@
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateSet("list","set","next","current")]
|
||||||
|
[string]$Action,
|
||||||
|
|
||||||
|
[int]$Index = -1
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'Stop'
|
||||||
|
|
||||||
|
Add-Type -TypeDefinition @'
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace JarvisAudio
|
||||||
|
{
|
||||||
|
[Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IMMDeviceEnumerator
|
||||||
|
{
|
||||||
|
[PreserveSig] int EnumAudioEndpoints(int dataFlow, int stateMask, out IMMDeviceCollection devices);
|
||||||
|
[PreserveSig] int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice device);
|
||||||
|
[PreserveSig] int GetDevice([MarshalAs(UnmanagedType.LPWStr)] string id, out IMMDevice device);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("0BD7A1BE-7A1A-44DB-8397-CC5392387B5E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IMMDeviceCollection
|
||||||
|
{
|
||||||
|
[PreserveSig] int GetCount(out int count);
|
||||||
|
[PreserveSig] int Item(int idx, out IMMDevice device);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IMMDevice
|
||||||
|
{
|
||||||
|
[PreserveSig] int Activate(ref Guid iid, int clsCtx, IntPtr activationParams, [MarshalAs(UnmanagedType.IUnknown)] out object iface);
|
||||||
|
[PreserveSig] int OpenPropertyStore(int access, out IPropertyStore store);
|
||||||
|
[PreserveSig] int GetId([MarshalAs(UnmanagedType.LPWStr)] out string id);
|
||||||
|
[PreserveSig] int GetState(out int state);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IPropertyStore
|
||||||
|
{
|
||||||
|
[PreserveSig] int GetCount(out int count);
|
||||||
|
[PreserveSig] int GetAt(int idx, out PROPERTYKEY key);
|
||||||
|
[PreserveSig] int GetValue(ref PROPERTYKEY key, out PROPVARIANT value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct PROPERTYKEY
|
||||||
|
{
|
||||||
|
public Guid formatId;
|
||||||
|
public int propertyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct PROPVARIANT
|
||||||
|
{
|
||||||
|
public ushort vt;
|
||||||
|
public ushort r1;
|
||||||
|
public ushort r2;
|
||||||
|
public ushort r3;
|
||||||
|
public IntPtr p;
|
||||||
|
public IntPtr p2;
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")]
|
||||||
|
public class MMDeviceEnumerator {}
|
||||||
|
|
||||||
|
[Guid("F8679F50-850A-41CF-9C72-430F290290C8"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||||
|
public interface IPolicyConfig
|
||||||
|
{
|
||||||
|
[PreserveSig] int GetMixFormat();
|
||||||
|
[PreserveSig] int GetDeviceFormat();
|
||||||
|
[PreserveSig] int ResetDeviceFormat();
|
||||||
|
[PreserveSig] int SetDeviceFormat();
|
||||||
|
[PreserveSig] int GetProcessingPeriod();
|
||||||
|
[PreserveSig] int SetProcessingPeriod();
|
||||||
|
[PreserveSig] int GetShareMode();
|
||||||
|
[PreserveSig] int SetShareMode();
|
||||||
|
[PreserveSig] int GetPropertyValue();
|
||||||
|
[PreserveSig] int SetPropertyValue();
|
||||||
|
[PreserveSig] int SetDefaultEndpoint([MarshalAs(UnmanagedType.LPWStr)] string deviceId, uint role);
|
||||||
|
[PreserveSig] int SetEndpointVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComImport, Guid("870AF99C-171D-4F9E-AF0D-E63DF40C2BC9")]
|
||||||
|
public class PolicyConfigClient {}
|
||||||
|
|
||||||
|
public class Device
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Manager
|
||||||
|
{
|
||||||
|
const int eRender = 0;
|
||||||
|
const int DEVICE_STATE_ACTIVE = 1;
|
||||||
|
|
||||||
|
static PROPERTYKEY PKEY_Device_FriendlyName = new PROPERTYKEY {
|
||||||
|
formatId = new Guid("a45c254e-df1c-4efd-8020-67d146a850e0"),
|
||||||
|
propertyId = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
public static List<Device> ListRender()
|
||||||
|
{
|
||||||
|
var enumr = (IMMDeviceEnumerator)new MMDeviceEnumerator();
|
||||||
|
IMMDeviceCollection coll;
|
||||||
|
int hr = enumr.EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, out coll);
|
||||||
|
if (hr != 0) throw new Exception("EnumAudioEndpoints failed: 0x" + hr.ToString("X"));
|
||||||
|
|
||||||
|
int count;
|
||||||
|
coll.GetCount(out count);
|
||||||
|
|
||||||
|
var result = new List<Device>();
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
IMMDevice dev;
|
||||||
|
coll.Item(i, out dev);
|
||||||
|
string id;
|
||||||
|
dev.GetId(out id);
|
||||||
|
|
||||||
|
IPropertyStore store;
|
||||||
|
dev.OpenPropertyStore(0, out store);
|
||||||
|
|
||||||
|
PROPVARIANT v;
|
||||||
|
store.GetValue(ref PKEY_Device_FriendlyName, out v);
|
||||||
|
string name = v.p != IntPtr.Zero ? Marshal.PtrToStringUni(v.p) : "(unknown)";
|
||||||
|
|
||||||
|
result.Add(new Device { Id = id, Name = name });
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetDefaultRenderId()
|
||||||
|
{
|
||||||
|
var enumr = (IMMDeviceEnumerator)new MMDeviceEnumerator();
|
||||||
|
IMMDevice dev;
|
||||||
|
int hr = enumr.GetDefaultAudioEndpoint(eRender, 0, out dev); // eConsole = 0
|
||||||
|
if (hr != 0) return null;
|
||||||
|
string id;
|
||||||
|
dev.GetId(out id);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetDefault(string deviceId)
|
||||||
|
{
|
||||||
|
var cfg = (IPolicyConfig)new PolicyConfigClient();
|
||||||
|
cfg.SetDefaultEndpoint(deviceId, 0); // eConsole
|
||||||
|
cfg.SetDefaultEndpoint(deviceId, 1); // eMultimedia
|
||||||
|
cfg.SetDefaultEndpoint(deviceId, 2); // eCommunications
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'@ -Language CSharp
|
||||||
|
|
||||||
|
$devs = [JarvisAudio.Manager]::ListRender()
|
||||||
|
|
||||||
|
switch ($Action) {
|
||||||
|
"list" {
|
||||||
|
for ($i = 0; $i -lt $devs.Count; $i++) {
|
||||||
|
Write-Output ("{0}`t{1}" -f $i, $devs[$i].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"current" {
|
||||||
|
$cur = [JarvisAudio.Manager]::GetDefaultRenderId()
|
||||||
|
for ($i = 0; $i -lt $devs.Count; $i++) {
|
||||||
|
if ($devs[$i].Id -eq $cur) {
|
||||||
|
Write-Output ("{0}`t{1}" -f $i, $devs[$i].Name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write-Output "-1`t(unknown)"
|
||||||
|
}
|
||||||
|
"set" {
|
||||||
|
if ($Index -lt 0 -or $Index -ge $devs.Count) {
|
||||||
|
Write-Error "Index out of range: $Index (have $($devs.Count) devices)"
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
[JarvisAudio.Manager]::SetDefault($devs[$Index].Id)
|
||||||
|
Write-Output ("OK`t{0}" -f $devs[$Index].Name)
|
||||||
|
}
|
||||||
|
"next" {
|
||||||
|
$cur = [JarvisAudio.Manager]::GetDefaultRenderId()
|
||||||
|
$curIdx = -1
|
||||||
|
for ($i = 0; $i -lt $devs.Count; $i++) {
|
||||||
|
if ($devs[$i].Id -eq $cur) { $curIdx = $i; break }
|
||||||
|
}
|
||||||
|
$nextIdx = ($curIdx + 1) % $devs.Count
|
||||||
|
[JarvisAudio.Manager]::SetDefault($devs[$nextIdx].Id)
|
||||||
|
Write-Output ("OK`t{0}" -f $devs[$nextIdx].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
55
resources/commands/output_device/command.toml
Normal file
55
resources/commands/output_device/command.toml
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "list_output_devices"
|
||||||
|
type = "lua"
|
||||||
|
script = "list_devices.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 8000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"какие устройства вывода",
|
||||||
|
"покажи устройства",
|
||||||
|
"список устройств",
|
||||||
|
"какие наушники",
|
||||||
|
"какие колонки",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"list output devices",
|
||||||
|
"show audio devices",
|
||||||
|
"list speakers",
|
||||||
|
"what audio devices",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"які пристрої виводу",
|
||||||
|
"покажи пристрої",
|
||||||
|
"список пристроїв",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "next_output_device"
|
||||||
|
type = "lua"
|
||||||
|
script = "next_device.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 8000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"переключи устройство",
|
||||||
|
"переключи звук",
|
||||||
|
"следующее устройство",
|
||||||
|
"смени вывод",
|
||||||
|
"переключи на наушники",
|
||||||
|
"переключи на колонки",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"switch audio device",
|
||||||
|
"next audio device",
|
||||||
|
"switch output",
|
||||||
|
"switch speakers",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"перемкни пристрій",
|
||||||
|
"перемкни звук",
|
||||||
|
"наступний пристрій",
|
||||||
|
]
|
||||||
31
resources/commands/output_device/list_devices.lua
Normal file
31
resources/commands/output_device/list_devices.lua
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
local lang = jarvis.context.language
|
||||||
|
local helper = jarvis.context.command_path .. "\\_audio_devices.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action list',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if not res.success then
|
||||||
|
jarvis.log("error", "list devices failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
return { chain = false }
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
for line in (res.stdout or ""):gmatch("[^\r\n]+") do
|
||||||
|
if line ~= "" then table.insert(lines, line) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local title = lang == "ru" and "Устройства вывода" or "Output devices"
|
||||||
|
local body
|
||||||
|
if #lines == 0 then
|
||||||
|
body = lang == "ru" and "Активных устройств не найдено" or "No active devices"
|
||||||
|
else
|
||||||
|
body = table.concat(lines, "\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
jarvis.system.notify(title, body)
|
||||||
|
jarvis.log("info", "audio devices: " .. body)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
return { chain = false }
|
||||||
22
resources/commands/output_device/next_device.lua
Normal file
22
resources/commands/output_device/next_device.lua
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
local lang = jarvis.context.language
|
||||||
|
local helper = jarvis.context.command_path .. "\\_audio_devices.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action next',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if not res.success then
|
||||||
|
jarvis.log("error", "next device failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
return { chain = false }
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
local name = out:match("^OK\t(.+)$") or out
|
||||||
|
|
||||||
|
local title = lang == "ru" and "Аудио переключено" or "Audio switched"
|
||||||
|
jarvis.system.notify(title, name)
|
||||||
|
jarvis.log("info", "audio switched to: " .. name)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
return { chain = false }
|
||||||
69
resources/commands/sysinfo/_sysinfo.ps1
Normal file
69
resources/commands/sysinfo/_sysinfo.ps1
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateSet("battery","time","cpu","ram","disk","all")]
|
||||||
|
[string]$Topic
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
|
function Get-BatteryInfo {
|
||||||
|
$b = Get-CimInstance -ClassName Win32_Battery
|
||||||
|
if (-not $b) { return "Батарея не обнаружена (видимо, десктоп)" }
|
||||||
|
$pct = [int]$b.EstimatedChargeRemaining
|
||||||
|
$status = switch ($b.BatteryStatus) {
|
||||||
|
1 { "разряжается" }
|
||||||
|
2 { "от сети" }
|
||||||
|
3 { "заряжена" }
|
||||||
|
4 { "низкий заряд" }
|
||||||
|
5 { "критический заряд" }
|
||||||
|
default { "статус $($b.BatteryStatus)" }
|
||||||
|
}
|
||||||
|
return "Батарея: $pct%, $status"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-TimeInfo {
|
||||||
|
$ru = [System.Globalization.CultureInfo]::GetCultureInfo("ru-RU")
|
||||||
|
$now = Get-Date
|
||||||
|
return "Сейчас: " + $now.ToString("HH:mm, dd MMMM, dddd", $ru)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-CpuInfo {
|
||||||
|
$cpu = Get-CimInstance -ClassName Win32_Processor | Select-Object -First 1
|
||||||
|
$load = (Get-CimInstance -ClassName Win32_PerfFormattedData_PerfOS_Processor -Filter "Name='_Total'" -ErrorAction SilentlyContinue).PercentProcessorTime
|
||||||
|
if ($null -eq $load) { $load = $cpu.LoadPercentage }
|
||||||
|
return "CPU: $($cpu.Name.Trim()), загрузка $load%"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-RamInfo {
|
||||||
|
$os = Get-CimInstance -ClassName Win32_OperatingSystem
|
||||||
|
$totalGB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 1)
|
||||||
|
$freeGB = [math]::Round($os.FreePhysicalMemory / 1MB, 1)
|
||||||
|
$usedGB = [math]::Round($totalGB - $freeGB, 1)
|
||||||
|
$pct = [int](($usedGB / $totalGB) * 100)
|
||||||
|
return "RAM: $usedGB из $totalGB ГБ ($pct% занято)"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-DiskInfo {
|
||||||
|
$sys = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DeviceID='$($env:SystemDrive)'"
|
||||||
|
if (-not $sys) {
|
||||||
|
$sys = Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" | Select-Object -First 1
|
||||||
|
}
|
||||||
|
$freeGB = [math]::Round($sys.FreeSpace / 1GB, 1)
|
||||||
|
$totalGB = [math]::Round($sys.Size / 1GB, 1)
|
||||||
|
return "Диск $($sys.DeviceID): свободно $freeGB из $totalGB ГБ"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($Topic) {
|
||||||
|
"battery" { Get-BatteryInfo }
|
||||||
|
"time" { Get-TimeInfo }
|
||||||
|
"cpu" { Get-CpuInfo }
|
||||||
|
"ram" { Get-RamInfo }
|
||||||
|
"disk" { Get-DiskInfo }
|
||||||
|
"all" {
|
||||||
|
Get-TimeInfo
|
||||||
|
Get-BatteryInfo
|
||||||
|
Get-CpuInfo
|
||||||
|
Get-RamInfo
|
||||||
|
Get-DiskInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
13
resources/commands/sysinfo/all.lua
Normal file
13
resources/commands/sysinfo/all.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic all', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("Статус системы", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "sysinfo all failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/sysinfo/battery.lua
Normal file
13
resources/commands/sysinfo/battery.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic battery', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("Батарея", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "battery info failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
152
resources/commands/sysinfo/command.toml
Normal file
152
resources/commands/sysinfo/command.toml
Normal file
|
|
@ -0,0 +1,152 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_battery"
|
||||||
|
type = "lua"
|
||||||
|
script = "battery.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"сколько заряда",
|
||||||
|
"сколько батарея",
|
||||||
|
"заряд батареи",
|
||||||
|
"сколько процентов",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"battery level",
|
||||||
|
"how much battery",
|
||||||
|
"battery status",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"скільки заряду",
|
||||||
|
"заряд батареї",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_time"
|
||||||
|
type = "lua"
|
||||||
|
script = "time.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"сколько времени",
|
||||||
|
"который час",
|
||||||
|
"сколько сейчас времени",
|
||||||
|
"какой день",
|
||||||
|
"какое сегодня число",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"what time is it",
|
||||||
|
"current time",
|
||||||
|
"what day is it",
|
||||||
|
"what is the date",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"котра година",
|
||||||
|
"скільки часу",
|
||||||
|
"який сьогодні день",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_cpu"
|
||||||
|
type = "lua"
|
||||||
|
script = "cpu.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 8000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"загрузка процессора",
|
||||||
|
"сколько процессор",
|
||||||
|
"нагрузка цпу",
|
||||||
|
"что с процессором",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"cpu load",
|
||||||
|
"cpu usage",
|
||||||
|
"how is cpu",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"завантаження процесора",
|
||||||
|
"як процесор",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_ram"
|
||||||
|
type = "lua"
|
||||||
|
script = "ram.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"сколько памяти",
|
||||||
|
"сколько оперативки",
|
||||||
|
"загрузка оперативки",
|
||||||
|
"сколько свободной памяти",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"how much ram",
|
||||||
|
"ram usage",
|
||||||
|
"memory usage",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"скільки пам'яті",
|
||||||
|
"скільки оперативки",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_disk"
|
||||||
|
type = "lua"
|
||||||
|
script = "disk.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 5000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"сколько свободно на диске",
|
||||||
|
"сколько места на диске",
|
||||||
|
"сколько места на жёстком",
|
||||||
|
"сколько свободно",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"free disk space",
|
||||||
|
"how much disk space",
|
||||||
|
"disk usage",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"скільки вільно на диску",
|
||||||
|
"скільки місця на диску",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "sysinfo_all"
|
||||||
|
type = "lua"
|
||||||
|
script = "all.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 10000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"статус системы",
|
||||||
|
"что с компьютером",
|
||||||
|
"состояние пк",
|
||||||
|
"что по системе",
|
||||||
|
"статус",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"system status",
|
||||||
|
"how is the system",
|
||||||
|
"pc status",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"статус системи",
|
||||||
|
"стан пк",
|
||||||
|
]
|
||||||
13
resources/commands/sysinfo/cpu.lua
Normal file
13
resources/commands/sysinfo/cpu.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic cpu', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("CPU", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "cpu info failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/sysinfo/disk.lua
Normal file
13
resources/commands/sysinfo/disk.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic disk', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("Диск", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "disk info failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/sysinfo/ram.lua
Normal file
13
resources/commands/sysinfo/ram.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic ram', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("Память", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "ram info failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
13
resources/commands/sysinfo/time.lua
Normal file
13
resources/commands/sysinfo/time.lua
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_sysinfo.ps1"
|
||||||
|
local cmd = string.format('powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Topic time', helper)
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
local text = (res.stdout or ""):gsub("[\r\n]+$", "")
|
||||||
|
if res.success and text ~= "" then
|
||||||
|
jarvis.system.notify("Время", text)
|
||||||
|
jarvis.log("info", text)
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "time info failed: " .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
return { chain = false }
|
||||||
31
resources/commands/volume/_volume_helper.ps1
Normal file
31
resources/commands/volume/_volume_helper.ps1
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateSet("up","down","mute","max")]
|
||||||
|
[string]$Action,
|
||||||
|
|
||||||
|
[int]$Times = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
Add-Type -Name VolumeKey -Namespace Win32 -MemberDefinition @'
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, System.UIntPtr dwExtraInfo);
|
||||||
|
'@
|
||||||
|
|
||||||
|
$KEY_UP = 0xAF
|
||||||
|
$KEY_DOWN = 0xAE
|
||||||
|
$KEY_MUTE = 0xAD
|
||||||
|
|
||||||
|
$vk = switch ($Action) {
|
||||||
|
"up" { $KEY_UP }
|
||||||
|
"down" { $KEY_DOWN }
|
||||||
|
"mute" { $KEY_MUTE }
|
||||||
|
"max" { $KEY_UP }
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = if ($Action -eq "max") { 50 } else { $Times }
|
||||||
|
|
||||||
|
for ($i = 0; $i -lt $count; $i++) {
|
||||||
|
[Win32.VolumeKey]::keybd_event($vk, 0, 0, [UIntPtr]::Zero)
|
||||||
|
[Win32.VolumeKey]::keybd_event($vk, 0, 2, [UIntPtr]::Zero)
|
||||||
|
Start-Sleep -Milliseconds 25
|
||||||
|
}
|
||||||
106
resources/commands/volume/command.toml
Normal file
106
resources/commands/volume/command.toml
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
[[commands]]
|
||||||
|
id = "volume_up"
|
||||||
|
type = "lua"
|
||||||
|
script = "volume_up.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"громче",
|
||||||
|
"сделай громче",
|
||||||
|
"прибавь звук",
|
||||||
|
"увеличь громкость",
|
||||||
|
"погромче",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"louder",
|
||||||
|
"volume up",
|
||||||
|
"increase volume",
|
||||||
|
"turn it up",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"голосніше",
|
||||||
|
"зроби голосніше",
|
||||||
|
"збільш гучність",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "volume_down"
|
||||||
|
type = "lua"
|
||||||
|
script = "volume_down.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"тише",
|
||||||
|
"сделай тише",
|
||||||
|
"убавь звук",
|
||||||
|
"уменьши громкость",
|
||||||
|
"потише",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"quieter",
|
||||||
|
"volume down",
|
||||||
|
"decrease volume",
|
||||||
|
"turn it down",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"тихіше",
|
||||||
|
"зроби тихіше",
|
||||||
|
"зменш гучність",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "volume_mute"
|
||||||
|
type = "lua"
|
||||||
|
script = "volume_mute.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"выключи звук",
|
||||||
|
"заткнись",
|
||||||
|
"тишина",
|
||||||
|
"приглуши звук",
|
||||||
|
"отключи звук",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"mute",
|
||||||
|
"silence",
|
||||||
|
"shut up",
|
||||||
|
"be quiet",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"вимкни звук",
|
||||||
|
"тиша",
|
||||||
|
"стихни",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[[commands]]
|
||||||
|
id = "volume_max"
|
||||||
|
type = "lua"
|
||||||
|
script = "volume_max.lua"
|
||||||
|
sandbox = "full"
|
||||||
|
timeout = 3000
|
||||||
|
|
||||||
|
[commands.phrases]
|
||||||
|
ru = [
|
||||||
|
"максимальная громкость",
|
||||||
|
"звук на максимум",
|
||||||
|
"на полную",
|
||||||
|
]
|
||||||
|
en = [
|
||||||
|
"max volume",
|
||||||
|
"full volume",
|
||||||
|
"maximum",
|
||||||
|
]
|
||||||
|
ua = [
|
||||||
|
"максимальна гучність",
|
||||||
|
"звук на максимум",
|
||||||
|
]
|
||||||
16
resources/commands/volume/volume_down.lua
Normal file
16
resources/commands/volume/volume_down.lua
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_volume_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action down -Times 5',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.log("info", "volume down")
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "volume down failed: code=" .. tostring(res.code) .. " stderr=" .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
16
resources/commands/volume/volume_max.lua
Normal file
16
resources/commands/volume/volume_max.lua
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_volume_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action max',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.log("info", "volume max")
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "volume max failed: code=" .. tostring(res.code) .. " stderr=" .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
16
resources/commands/volume/volume_mute.lua
Normal file
16
resources/commands/volume/volume_mute.lua
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_volume_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action mute',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.log("info", "mute toggled")
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "mute failed: code=" .. tostring(res.code) .. " stderr=" .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
16
resources/commands/volume/volume_up.lua
Normal file
16
resources/commands/volume/volume_up.lua
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
local helper = jarvis.context.command_path .. "\\_volume_helper.ps1"
|
||||||
|
local cmd = string.format(
|
||||||
|
'powershell -NoProfile -ExecutionPolicy Bypass -File "%s" -Action up -Times 5',
|
||||||
|
helper
|
||||||
|
)
|
||||||
|
|
||||||
|
local res = jarvis.system.exec(cmd)
|
||||||
|
if res.success then
|
||||||
|
jarvis.log("info", "volume up")
|
||||||
|
jarvis.audio.play_ok()
|
||||||
|
else
|
||||||
|
jarvis.log("error", "volume up failed: code=" .. tostring(res.code) .. " stderr=" .. tostring(res.stderr))
|
||||||
|
jarvis.audio.play_error()
|
||||||
|
end
|
||||||
|
|
||||||
|
return { chain = false }
|
||||||
|
|
@ -24,8 +24,8 @@ type = "lua"
|
||||||
script = "set_city.lua"
|
script = "set_city.lua"
|
||||||
sandbox = "standard"
|
sandbox = "standard"
|
||||||
timeout = 5000
|
timeout = 5000
|
||||||
phrases = [
|
|
||||||
"установи город",
|
[commands.phrases]
|
||||||
"set city",
|
ru = ["установи город", "смени город", "поменяй город"]
|
||||||
"change city",
|
en = ["set city", "change city"]
|
||||||
]
|
ua = ["встанови місто", "змін місто"]
|
||||||
Loading…
Add table
Add a link
Reference in a new issue