first commit
This commit is contained in:
BIN
callbacks/__pycache__/example.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/example.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/lock.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/lock.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/media.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/media.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/screen.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/screen.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/system.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/system.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/v2ray.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/v2ray.cpython-311.pyc
Normal file
Binary file not shown.
BIN
callbacks/__pycache__/web.cpython-311.pyc
Normal file
BIN
callbacks/__pycache__/web.cpython-311.pyc
Normal file
Binary file not shown.
5
callbacks/example.py
Normal file
5
callbacks/example.py
Normal file
@@ -0,0 +1,5 @@
|
||||
async def example_action(args):
|
||||
return {"message": "Example action executed", "args": args}
|
||||
|
||||
def another_action(args):
|
||||
return {"message": "Another action executed synchronously", "args": args}
|
||||
21
callbacks/lock.py
Normal file
21
callbacks/lock.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import ctypes
|
||||
from typing import Dict, Any
|
||||
|
||||
async def lock_computer(args: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Locks the Windows computer screen using the LockWorkStation API.
|
||||
Args:
|
||||
args: Dictionary of arguments (not used in this implementation).
|
||||
Returns:
|
||||
Dictionary with status message and input arguments.
|
||||
Raises:
|
||||
OSError: If the lock operation fails or the platform is not Windows.
|
||||
"""
|
||||
try:
|
||||
# Use Windows API to lock the screen
|
||||
result = ctypes.WinDLL('user32.dll').LockWorkStation()
|
||||
if not result:
|
||||
raise OSError("Failed to lock the Windows screen")
|
||||
return {"message": "Windows screen locked successfully", "args": args}
|
||||
except Exception as e:
|
||||
raise OSError(f"Error while locking the Windows screen: {str(e)}")
|
||||
109
callbacks/media.py
Normal file
109
callbacks/media.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import sys
|
||||
import os
|
||||
import asyncio
|
||||
import comtypes
|
||||
import ctypes
|
||||
from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume
|
||||
from ctypes import cast, POINTER
|
||||
from typing import Dict, Any
|
||||
|
||||
from winrt.windows.media.control import GlobalSystemMediaTransportControlsSessionManager as MediaManager
|
||||
|
||||
|
||||
# Добавляем родительскую директорию в sys.path
|
||||
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
if parent_dir not in sys.path:
|
||||
sys.path.append(parent_dir)
|
||||
|
||||
|
||||
|
||||
|
||||
async def set_volume(args: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Sets the Windows system volume using the Core Audio API.
|
||||
|
||||
Args:
|
||||
args: Dictionary containing 'level' (float from 0.0 to 1.0) for volume level.
|
||||
|
||||
Returns:
|
||||
Dictionary with status message and input arguments.
|
||||
|
||||
Raises:
|
||||
OSError: If volume setting fails or the platform is not Windows.
|
||||
"""
|
||||
try:
|
||||
# Initialize COM
|
||||
comtypes.CoInitialize()
|
||||
|
||||
# Get volume level from args
|
||||
level = args.get('level', 0.5) # Default to 50% if not specified
|
||||
|
||||
# Validate input level
|
||||
if not isinstance(level, (int, float)) or not 0.0 <= level <= 1.0:
|
||||
raise ValueError("Volume level must be a float between 0.0 and 1.0")
|
||||
|
||||
# Get audio endpoint interface
|
||||
devices = AudioUtilities.GetSpeakers()
|
||||
interface = devices.Activate(IAudioEndpointVolume._iid_, comtypes.CLSCTX_ALL, None)
|
||||
volume = cast(interface, POINTER(IAudioEndpointVolume))
|
||||
|
||||
# Set volume level
|
||||
volume.SetMasterVolumeLevelScalar(float(level), None)
|
||||
|
||||
return {
|
||||
"message": f"Volume set to {level*100:.0f}% successfully",
|
||||
"args": args
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise OSError(f"Error while setting volume: {str(e)}")
|
||||
|
||||
finally:
|
||||
# Release COM resources
|
||||
comtypes.CoUninitialize()
|
||||
|
||||
async def play(args):
|
||||
# Получаем менеджер медиасессий
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
|
||||
if current_session:
|
||||
# Воспроизведение
|
||||
await current_session.try_play_async()
|
||||
else:
|
||||
print("No media session is active.")
|
||||
|
||||
async def pause(args):
|
||||
#print(await read_config("media.yaml"))
|
||||
# Получаем менеджер медиасессий
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
|
||||
if current_session:
|
||||
# пауза
|
||||
await current_session.try_pause_async()
|
||||
else:
|
||||
print("No media session is active.")
|
||||
|
||||
async def next(args):
|
||||
# Получаем менеджер медиасессий
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
|
||||
if current_session:
|
||||
# вперед
|
||||
await current_session.try_skip_next_async()
|
||||
# await show_notification({"title":"Test","message":"test"})
|
||||
else:
|
||||
print("No media session is active.")
|
||||
|
||||
async def prev(args):
|
||||
# Получаем менеджер медиасессий
|
||||
sessions = await MediaManager.request_async()
|
||||
current_session = sessions.get_current_session()
|
||||
|
||||
if current_session:
|
||||
# назад
|
||||
await current_session.try_skip_previous_async()
|
||||
else:
|
||||
print("No media session is active.")
|
||||
28
callbacks/screen.py
Normal file
28
callbacks/screen.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import monitorcontrol
|
||||
|
||||
def get_monitors():
|
||||
"""Retrieve a list of connected monitors."""
|
||||
return monitorcontrol.get_monitors()
|
||||
|
||||
def set_brightness(monitor, brightness):
|
||||
"""Set the brightness of a specific monitor."""
|
||||
if not 0 <= brightness <= 100:
|
||||
raise ValueError("Brightness must be between 0 and 100")
|
||||
with monitor:
|
||||
monitor.set_luminance(brightness)
|
||||
print(f"Set brightness to {brightness}%")
|
||||
|
||||
|
||||
def chenge_brightness(args):
|
||||
try:
|
||||
level = args.get('level', 10)
|
||||
monitors = get_monitors()
|
||||
if not monitors:
|
||||
raise OSError(f"No DDC/CI compatible monitors found.")
|
||||
return
|
||||
|
||||
for i, monitor in enumerate(monitors):
|
||||
set_brightness(monitor, level)
|
||||
|
||||
except Exception as e:
|
||||
raise OSError(f"An error occurred: {e}")
|
||||
86
callbacks/system.py
Normal file
86
callbacks/system.py
Normal file
@@ -0,0 +1,86 @@
|
||||
import asyncio
|
||||
import psutil
|
||||
import pynvml
|
||||
import time
|
||||
from typing import Dict, Any
|
||||
|
||||
async def get_system_metrics(args: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Retrieves system metrics including CPU usage, RAM usage, GPU usage (for NVIDIA GPUs),
|
||||
system uptime, and network traffic of the primary network interface.
|
||||
|
||||
Args:
|
||||
args: Dictionary of arguments (not used in this implementation).
|
||||
|
||||
Returns:
|
||||
Dictionary with CPU usage (%), RAM used (GB), RAM total (GB), GPU usage (%),
|
||||
system uptime (seconds), network traffic (Mbit/s), and input arguments.
|
||||
|
||||
Raises:
|
||||
OSError: If retrieving metrics fails.
|
||||
"""
|
||||
try:
|
||||
# Get CPU usage (averaged over 0.1 seconds for responsiveness)
|
||||
cpu_usage = await asyncio.to_thread(psutil.cpu_percent, interval=0.1)
|
||||
|
||||
# Get RAM usage
|
||||
memory = psutil.virtual_memory()
|
||||
ram_used = memory.used / (1024 ** 3) # Convert bytes to GB
|
||||
ram_total = memory.total / (1024 ** 3) # Convert bytes to GB
|
||||
|
||||
# Get system uptime
|
||||
uptime = time.time() - psutil.boot_time() # Time since system boot in seconds
|
||||
|
||||
# Get network traffic for primary interface
|
||||
network_traffic = 0.0
|
||||
net_io = psutil.net_io_counters(pernic=True)
|
||||
primary_interface = None
|
||||
max_bytes = 0
|
||||
|
||||
# Find primary network interface (with most bytes sent/received)
|
||||
for interface, stats in net_io.items():
|
||||
total_bytes = stats.bytes_sent + stats.bytes_recv
|
||||
if total_bytes > max_bytes:
|
||||
max_bytes = total_bytes
|
||||
primary_interface = interface
|
||||
|
||||
if primary_interface:
|
||||
# Measure traffic over 1 second
|
||||
initial_stats = net_io[primary_interface]
|
||||
await asyncio.sleep(1)
|
||||
final_stats = psutil.net_io_counters(pernic=True)[primary_interface]
|
||||
|
||||
# Calculate traffic in Mbit/s
|
||||
bytes_diff = (final_stats.bytes_sent - initial_stats.bytes_sent +
|
||||
final_stats.bytes_recv - initial_stats.bytes_recv)
|
||||
network_traffic = (bytes_diff * 8) / (1024 ** 2) # Convert bytes to Mbit/s
|
||||
|
||||
# Try to get GPU usage (NVIDIA only)
|
||||
gpu_usage = 0.0
|
||||
try:
|
||||
pynvml.nvmlInit()
|
||||
device_count = pynvml.nvmlDeviceGetCount()
|
||||
if device_count > 0:
|
||||
handle = pynvml.nvmlDeviceGetHandleByIndex(0) # Use first GPU
|
||||
utilization = pynvml.nvmlDeviceGetUtilizationRates(handle)
|
||||
gpu_usage = utilization.gpu
|
||||
pynvml.nvmlShutdown()
|
||||
except pynvml.NVMLError:
|
||||
gpu_usage = -1 # Indicate GPU metrics unavailable
|
||||
|
||||
return {
|
||||
"message": "System metrics retrieved successfully",
|
||||
"metrics": {
|
||||
"cpu_usage_percent": round(cpu_usage, 2),
|
||||
"ram_used_gb": round(ram_used, 2),
|
||||
"ram_total_gb": round(ram_total, 2),
|
||||
"gpu_usage_percent": gpu_usage,
|
||||
"uptime_seconds": round(uptime, 2),
|
||||
"network_traffic_mbps": round(network_traffic, 2)
|
||||
},
|
||||
"args": args
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise OSError(f"Error while retrieving system metrics: {str(e)}")
|
||||
|
||||
135
callbacks/v2ray.py
Normal file
135
callbacks/v2ray.py
Normal file
@@ -0,0 +1,135 @@
|
||||
import aiohttp
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
|
||||
# Добавляем родительскую директорию в sys.path
|
||||
parent_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
||||
if parent_dir not in sys.path:
|
||||
sys.path.append(parent_dir)
|
||||
|
||||
|
||||
from utils.windows_toast import show_notification
|
||||
from utils.config import read_config
|
||||
|
||||
|
||||
class V2rayAController:
|
||||
def __init__(self, host='http://localhost:2017', username='admin', password='admin'):
|
||||
self.host = host
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.token = None
|
||||
self.session = None
|
||||
|
||||
async def authenticate(self):
|
||||
"""Аутентификация и получение токена"""
|
||||
self.session = aiohttp.ClientSession()
|
||||
auth_url = f"{self.host}/api/login"
|
||||
credentials = {
|
||||
'username': self.username,
|
||||
'password': self.password
|
||||
}
|
||||
|
||||
try:
|
||||
async with self.session.post(auth_url, json=credentials) as response:
|
||||
if response.status == 200:
|
||||
data = await response.json()
|
||||
self.token = data.get('data').get('token')
|
||||
print("V2RayA auth OK")
|
||||
return True
|
||||
else:
|
||||
print(f"Ошибка аутентификации: {response.status}")
|
||||
return False
|
||||
except Exception as e:
|
||||
raise OSError("Failed to authenticate v2ray")
|
||||
print(f"Ошибка при аутентификации: {e}")
|
||||
return False
|
||||
|
||||
async def enable_proxy(self):
|
||||
"""Включение прокси"""
|
||||
if not self.token:
|
||||
print("Не выполнен вход. Пожалуйста, сначала выполните аутентификацию")
|
||||
return False
|
||||
|
||||
url = f"{self.host}/api/v2ray"
|
||||
headers = {'Authorization': f"Bearer {self.token}"}
|
||||
data = {}
|
||||
|
||||
try:
|
||||
async with self.session.post(url, headers=headers, json=data) as response:
|
||||
if response.status == 200:
|
||||
print("Прокси успешно включен")
|
||||
await show_notification({"title":"✅ V2Ray proxy","message":"Прокси успешно включен"})
|
||||
return True
|
||||
else:
|
||||
print(f"Ошибка при включении прокси: {response.status}")
|
||||
return False
|
||||
except Exception as e:
|
||||
raise OSError("Failed to enable proxy")
|
||||
print(f"Ошибка при включении прокси: {e}")
|
||||
return False
|
||||
|
||||
async def disable_proxy(self):
|
||||
"""Выключение прокси"""
|
||||
if not self.token:
|
||||
print("Не выполнен вход. Пожалуйста, сначала выполните аутентификацию")
|
||||
return False
|
||||
|
||||
url = f"{self.host}/api/v2ray"
|
||||
headers = {'Authorization': f"Bearer {self.token}"}
|
||||
data = {'operation': 'stop'}
|
||||
|
||||
try:
|
||||
async with self.session.delete(url, headers=headers, json=data) as response:
|
||||
if response.status == 200:
|
||||
print("Прокси успешно выключен")
|
||||
await show_notification({"title":"🔴 V2Ray proxy","message":"Прокси успешно выключен"})
|
||||
return True
|
||||
else:
|
||||
print(f"Ошибка при выключении прокси: {response.status}")
|
||||
return False
|
||||
except Exception as e:
|
||||
raise OSError("Failed to disable proxy")
|
||||
print(f"Ошибка при выключении прокси: {e}")
|
||||
return False
|
||||
|
||||
async def close(self):
|
||||
"""Закрытие сессии"""
|
||||
if self.session:
|
||||
await self.session.close()
|
||||
|
||||
async def enable_vpn(args):
|
||||
# Инициализация контроллера
|
||||
config = await read_config("v2ray.yaml")
|
||||
if config.get("username") and config.get("password"):
|
||||
controller = V2rayAController(
|
||||
host='http://localhost:2017',
|
||||
username=config.get("username"),
|
||||
password=config.get("password")
|
||||
)
|
||||
# Аутентификация
|
||||
if await controller.authenticate():
|
||||
await controller.enable_proxy()
|
||||
|
||||
# Закрытие сессии
|
||||
await controller.close()
|
||||
else:
|
||||
raise OSError("Config unset")
|
||||
async def disable_vpn(args):
|
||||
# Инициализация контроллера
|
||||
config = await read_config("v2ray.yaml")
|
||||
if config.get("username") and config.get("password"):
|
||||
controller = V2rayAController(
|
||||
host='http://localhost:2017',
|
||||
username=config.get("username"),
|
||||
password=config.get("password")
|
||||
)
|
||||
# Аутентификация
|
||||
if await controller.authenticate():
|
||||
await controller.disable_proxy()
|
||||
|
||||
# Закрытие сессии
|
||||
await controller.close()
|
||||
else:
|
||||
raise OSError("Config unset")
|
||||
39
callbacks/web.py
Normal file
39
callbacks/web.py
Normal file
@@ -0,0 +1,39 @@
|
||||
import asyncio
|
||||
import webbrowser
|
||||
from typing import Dict, Any
|
||||
|
||||
async def open_url(args: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Opens a website in the default browser on Windows.
|
||||
|
||||
Args:
|
||||
args: Dictionary containing 'url' (string) of the website to open.
|
||||
|
||||
Returns:
|
||||
Dictionary with status message and input arguments.
|
||||
|
||||
Raises:
|
||||
OSError: If opening the website fails.
|
||||
"""
|
||||
try:
|
||||
# Get URL from args
|
||||
url = args.get('url')
|
||||
if not url:
|
||||
raise ValueError("URL must be provided in args")
|
||||
|
||||
# Ensure URL has a scheme (http:// or https://)
|
||||
if not url.startswith(('http://', 'https://')):
|
||||
url = 'https://' + url
|
||||
|
||||
# Open website in default browser
|
||||
success = await asyncio.to_thread(webbrowser.open, url)
|
||||
if not success:
|
||||
raise OSError("Failed to open the website")
|
||||
|
||||
return {
|
||||
"message": f"Website {url} opened successfully",
|
||||
"args": args
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise OSError(f"Error while opening website: {str(e)}")
|
||||
Reference in New Issue
Block a user