Merge branch 'main' into zdy
This commit is contained in:
@@ -1,13 +1,9 @@
|
||||
import ctypes
|
||||
import os
|
||||
from pathlib import Path
|
||||
import platform
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
from pyxcursor import Xcursor
|
||||
# import Xlib.display
|
||||
import pyautogui
|
||||
# from PIL import ImageGrab, Image
|
||||
from PIL import Image
|
||||
import lxml.etree
|
||||
from lxml.etree import _Element
|
||||
import pyatspi
|
||||
@@ -17,12 +13,19 @@ from pyatspi import Text as ATText
|
||||
from pyatspi import Value as ATValue
|
||||
from pyatspi import Action as ATAction
|
||||
|
||||
import requests
|
||||
from flask import Flask, request, jsonify, send_file
|
||||
|
||||
from typing import List, Dict
|
||||
from typing import Any
|
||||
|
||||
import Xlib
|
||||
import pyautogui
|
||||
from PIL import Image
|
||||
from Xlib import display, X
|
||||
from pyxcursor import Xcursor
|
||||
|
||||
import requests
|
||||
from flask import Flask, request, jsonify, send_file, abort
|
||||
from werkzeug.utils import secure_filename
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
pyautogui.PAUSE = 0
|
||||
@@ -30,6 +33,7 @@ pyautogui.DARWIN_CATCH_UP_TIME = 0
|
||||
|
||||
logger = app.logger
|
||||
|
||||
|
||||
@app.route('/setup/execute', methods=['POST'])
|
||||
@app.route('/execute', methods=['POST'])
|
||||
def execute_command():
|
||||
@@ -52,6 +56,7 @@ def execute_command():
|
||||
'message': str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
@app.route('/setup/launch', methods=["POST"])
|
||||
def launch_app():
|
||||
data = request.json
|
||||
@@ -61,11 +66,7 @@ def launch_app():
|
||||
subprocess.Popen(command)
|
||||
return "{:} launched successfully".format(" ".join(command))
|
||||
except Exception as e:
|
||||
return jsonify( { "status": "error"
|
||||
, "message": str(e)
|
||||
}
|
||||
)\
|
||||
, 500
|
||||
return jsonify({"status": "error", "message": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/screenshot', methods=['GET'])
|
||||
@@ -248,6 +249,164 @@ def get_accessibility_tree():
|
||||
desktop_xml: _Element = _create_node(desktop)
|
||||
return jsonify({"AT": lxml.etree.tostring(desktop_xml, encoding="unicode")})
|
||||
|
||||
@app.route('/screen_size', methods=['POST'])
|
||||
def get_screen_size():
|
||||
d = display.Display()
|
||||
screen_width = d.screen().width_in_pixels
|
||||
screen_height = d.screen().height_in_pixels
|
||||
return jsonify(
|
||||
{
|
||||
"width": screen_width,
|
||||
"height": screen_height
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@app.route('/window_size', methods=['POST'])
|
||||
def get_window_size():
|
||||
if 'app_class_name' in request.form:
|
||||
app_class_name = request.form['app_class_name']
|
||||
else:
|
||||
return jsonify({"error": "app_class_name is required"}), 400
|
||||
|
||||
d = display.Display()
|
||||
root = d.screen().root
|
||||
window_ids = root.get_full_property(d.intern_atom('_NET_CLIENT_LIST'), X.AnyPropertyType).value
|
||||
|
||||
for window_id in window_ids:
|
||||
try:
|
||||
window = d.create_resource_object('window', window_id)
|
||||
wm_class = window.get_wm_class()
|
||||
|
||||
if wm_class is None:
|
||||
continue
|
||||
|
||||
if app_class_name.lower() in [name.lower() for name in wm_class]:
|
||||
geom = window.get_geometry()
|
||||
return jsonify(
|
||||
{
|
||||
"width": geom.width,
|
||||
"height": geom.height
|
||||
}
|
||||
)
|
||||
except Xlib.error.XError: # Ignore windows that give an error
|
||||
continue
|
||||
return None
|
||||
|
||||
|
||||
@app.route('/desktop_path', methods=['POST'])
|
||||
def get_desktop_path():
|
||||
# Get the home directory in a platform-independent manner using pathlib
|
||||
home_directory = str(Path.home())
|
||||
|
||||
# Determine the desktop path based on the operating system
|
||||
desktop_path = {
|
||||
"Windows": os.path.join(home_directory, "Desktop"),
|
||||
"Darwin": os.path.join(home_directory, "Desktop"), # macOS
|
||||
"Linux": os.path.join(home_directory, "Desktop")
|
||||
}.get(platform.system(), None)
|
||||
|
||||
# Check if the operating system is supported and the desktop path exists
|
||||
if desktop_path and os.path.exists(desktop_path):
|
||||
return jsonify(desktop_path=desktop_path)
|
||||
else:
|
||||
return jsonify(error="Unsupported operating system or desktop path not found"), 404
|
||||
|
||||
|
||||
@app.route('/wallpaper', methods=['POST'])
|
||||
def get_wallpaper():
|
||||
def get_wallpaper_windows():
|
||||
SPI_GETDESKWALLPAPER = 0x73
|
||||
MAX_PATH = 260
|
||||
buffer = ctypes.create_unicode_buffer(MAX_PATH)
|
||||
ctypes.windll.user32.SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, buffer, 0)
|
||||
return buffer.value
|
||||
|
||||
def get_wallpaper_macos():
|
||||
script = """
|
||||
tell application "System Events" to tell every desktop to get picture
|
||||
"""
|
||||
process = subprocess.Popen(['osascript', '-e', script], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
output, error = process.communicate()
|
||||
if error:
|
||||
app.logger.error("Error: %s", error.decode('utf-8'))
|
||||
return None
|
||||
return output.strip().decode('utf-8')
|
||||
|
||||
def get_wallpaper_linux():
|
||||
try:
|
||||
output = subprocess.check_output(
|
||||
["gsettings", "get", "org.gnome.desktop.background", "picture-uri"],
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
return output.decode('utf-8').strip().replace('file://', '').replace("'", "")
|
||||
except subprocess.CalledProcessError as e:
|
||||
app.logger.error("Error: %s", e)
|
||||
return None
|
||||
|
||||
os_name = platform.system()
|
||||
wallpaper_path = None
|
||||
if os_name == 'Windows':
|
||||
wallpaper_path = get_wallpaper_windows()
|
||||
elif os_name == 'Darwin':
|
||||
wallpaper_path = get_wallpaper_macos()
|
||||
elif os_name == 'Linux':
|
||||
wallpaper_path = get_wallpaper_linux()
|
||||
else:
|
||||
app.logger.error(f"Unsupported OS: {os_name}")
|
||||
abort(400, description="Unsupported OS")
|
||||
|
||||
if wallpaper_path:
|
||||
try:
|
||||
# Ensure the filename is secure
|
||||
filename = secure_filename(os.path.basename(wallpaper_path))
|
||||
return send_file(wallpaper_path, attachment_filename=filename)
|
||||
except Exception as e:
|
||||
app.logger.error(f"An error occurred while serving the wallpaper file: {e}")
|
||||
abort(500, description="Unable to serve the wallpaper file")
|
||||
else:
|
||||
abort(404, description="Wallpaper file not found")
|
||||
|
||||
|
||||
@app.route('/list_directory', methods=['POST'])
|
||||
def get_directory_tree():
|
||||
def _list_dir_contents(directory):
|
||||
"""
|
||||
List the contents of a directory recursively, building a tree structure.
|
||||
|
||||
:param directory: The path of the directory to inspect.
|
||||
:return: A nested dictionary with the contents of the directory.
|
||||
"""
|
||||
tree = {'type': 'directory', 'name': os.path.basename(directory), 'children': []}
|
||||
try:
|
||||
# List all files and directories in the current directory
|
||||
for entry in os.listdir(directory):
|
||||
full_path = os.path.join(directory, entry)
|
||||
# If entry is a directory, recurse into it
|
||||
if os.path.isdir(full_path):
|
||||
tree['children'].append(_list_dir_contents(full_path))
|
||||
else:
|
||||
tree['children'].append({'type': 'file', 'name': entry})
|
||||
except OSError as e:
|
||||
# If the directory cannot be accessed, return the exception message
|
||||
tree = {'error': str(e)}
|
||||
return tree
|
||||
|
||||
# Extract the 'path' parameter from the JSON request
|
||||
data = request.get_json()
|
||||
if 'path' not in data:
|
||||
return jsonify(error="Missing 'path' parameter"), 400
|
||||
|
||||
start_path = data['path']
|
||||
# Ensure the provided path is a directory
|
||||
if not os.path.isdir(start_path):
|
||||
return jsonify(error="The provided path is not a directory"), 400
|
||||
|
||||
# Generate the directory tree starting from the provided path
|
||||
directory_tree = _list_dir_contents(start_path)
|
||||
return jsonify(directory_tree=directory_tree)
|
||||
|
||||
|
||||
@app.route('/file', methods=['POST'])
|
||||
def get_file():
|
||||
# Retrieve filename from the POST request
|
||||
@@ -263,6 +422,7 @@ def get_file():
|
||||
# If the file is not found, return a 404 error
|
||||
return jsonify({"error": "File not found"}), 404
|
||||
|
||||
|
||||
@app.route("/setup/upload", methods=["POST"])
|
||||
def upload_file():
|
||||
# Retrieve filename from the POST request
|
||||
@@ -274,6 +434,7 @@ def upload_file():
|
||||
else:
|
||||
return jsonify({"error": "file_path and file_data are required"}), 400
|
||||
|
||||
|
||||
@app.route('/platform', methods=['GET'])
|
||||
def get_platform():
|
||||
return platform.system()
|
||||
|
||||
Reference in New Issue
Block a user