fix(file_handlers): use keystroke Cmd+Return to start pptx slideshow
Replace unreliable AppleScript PowerPoint API (run slide show of settings) with System Events keystroke approach, matching proven behavior from the old MasterKey app. Opens the file, waits 3s for load, then sends Cmd+Return to start the slideshow from slide 1.
This commit is contained in:
@@ -2,14 +2,16 @@
|
|||||||
# deploy.sh — Deploy Aether Native Launcher to onsite Mac laptops
|
# deploy.sh — Deploy Aether Native Launcher to onsite Mac laptops
|
||||||
#
|
#
|
||||||
# USAGE:
|
# USAGE:
|
||||||
# ./deploy.sh <num> [num ...] Deploy to one or more laptops (e.g. 03 04 05)
|
# ./deploy.sh <num> [num ...] Deploy to one or more laptops (e.g. 03 04 05)
|
||||||
# ./deploy.sh all Deploy to all laptops in devices.conf
|
# ./deploy.sh all Deploy to all laptops in devices.conf
|
||||||
# ./deploy.sh --seed-only <num> Update seed.json only — skip .app copy
|
# ./deploy.sh --seed-only <num> Update seed.json only — skip .app copy
|
||||||
# ./deploy.sh --seed-only all
|
# ./deploy.sh --seed-only all
|
||||||
|
# ./deploy.sh --build <num> [num ...] Build first (npm run package:mac), then deploy
|
||||||
|
# ./deploy.sh --build all
|
||||||
#
|
#
|
||||||
# REQUIRES:
|
# REQUIRES:
|
||||||
# event.env — copy from event.env.example and fill in AETHER_API_KEY
|
# event.env — copy from event.env.example and fill in AETHER_API_KEY
|
||||||
# builds/ — run "npm run package:mac" first if .app is missing
|
# builds/ — pre-built, or use --build to build before deploying
|
||||||
#
|
#
|
||||||
# SSH keys must already be installed on each target (run ssh-copy-id once per laptop).
|
# SSH keys must already be installed on each target (run ssh-copy-id once per laptop).
|
||||||
|
|
||||||
@@ -24,6 +26,7 @@ BUILD_DIR="$SCRIPT_DIR/../builds"
|
|||||||
# ── Argument parsing ──────────────────────────────────────────────────────────
|
# ── Argument parsing ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
SEED_ONLY=false
|
SEED_ONLY=false
|
||||||
|
BUILD_FIRST=false
|
||||||
TARGETS=()
|
TARGETS=()
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
@@ -36,6 +39,7 @@ if [[ $# -eq 0 ]]; then usage; fi
|
|||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--seed-only) SEED_ONLY=true ;;
|
--seed-only) SEED_ONLY=true ;;
|
||||||
|
--build) BUILD_FIRST=true ;;
|
||||||
--help|-h) usage ;;
|
--help|-h) usage ;;
|
||||||
all) TARGETS+=("all") ;;
|
all) TARGETS+=("all") ;;
|
||||||
*) TARGETS+=("$1") ;;
|
*) TARGETS+=("$1") ;;
|
||||||
@@ -75,8 +79,8 @@ fi
|
|||||||
# Returns "ip device_id" for a laptop number, or empty if not found
|
# Returns "ip device_id" for a laptop number, or empty if not found
|
||||||
lookup_device() {
|
lookup_device() {
|
||||||
local num="$1"
|
local num="$1"
|
||||||
grep -E "^[[:space:]]*${num}[[:space:]]" "$DEVICES_FILE" \
|
grep -v '^[[:space:]]*#' "$DEVICES_FILE" \
|
||||||
| grep -v '^[[:space:]]*#' \
|
| grep -E "^[[:space:]]*${num}[[:space:]]" \
|
||||||
| awk '{print $2, $3}' \
|
| awk '{print $2, $3}' \
|
||||||
| head -1
|
| head -1
|
||||||
}
|
}
|
||||||
@@ -134,12 +138,14 @@ deploy_laptop() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo " Arch: $arch → copying $(basename "$bundle")..."
|
echo " Arch: $arch → syncing $(basename "$bundle")..."
|
||||||
scp -r "$bundle" "$SSH_USER@$ip:/Applications/aether_launcher.app" || {
|
# rsync --delete syncs contents in-place without removing the top-level .app dir.
|
||||||
echo " ERROR: scp failed."
|
# This preserves the inode so macOS Aliases and Desktop shortcuts keep working.
|
||||||
|
rsync -a --delete -e ssh "$bundle/" "$SSH_USER@$ip:/Applications/aether_launcher.app/" || {
|
||||||
|
echo " ERROR: rsync failed."
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
echo " .app copied."
|
echo " .app synced."
|
||||||
else
|
else
|
||||||
echo " (--seed-only: skipping .app copy)"
|
echo " (--seed-only: skipping .app copy)"
|
||||||
fi
|
fi
|
||||||
@@ -168,6 +174,19 @@ EOF
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Build if requested ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
if [[ "$BUILD_FIRST" == "true" ]]; then
|
||||||
|
echo "══════════════════════════════════════════════"
|
||||||
|
echo " Building: npm run package:mac"
|
||||||
|
echo "══════════════════════════════════════════════"
|
||||||
|
(cd "$SCRIPT_DIR/.." && npm run package:mac) || {
|
||||||
|
echo "ERROR: Build failed. Aborting deploy."
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
# ── Expand "all" target ───────────────────────────────────────────────────────
|
# ── Expand "all" target ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
EXPANDED_TARGETS=()
|
EXPANDED_TARGETS=()
|
||||||
|
|||||||
@@ -9,20 +9,20 @@
|
|||||||
# num ip event_device_id notes
|
# num ip event_device_id notes
|
||||||
01 192.168.32.101 tFLL1fLQfnk
|
01 192.168.32.101 tFLL1fLQfnk
|
||||||
02 192.168.32.102 rpbfunVPEzw
|
02 192.168.32.102 rpbfunVPEzw
|
||||||
03 192.168.32.103 1EPfPX8kfw8
|
# 03 192.168.32.103 1EPfPX8kfw8
|
||||||
04 192.168.32.104 zvgyLM5yieU
|
# 04 192.168.32.104 zvgyLM5yieU
|
||||||
05 192.168.32.105 QOc046GoeSc
|
# 05 192.168.32.105 QOc046GoeSc
|
||||||
06 192.168.32.106 2o8j6eb0L6s
|
# 06 192.168.32.106 2o8j6eb0L6s
|
||||||
07 192.168.32.107 Oa1tlxPEVSQ
|
07 192.168.32.107 Oa1tlxPEVSQ
|
||||||
08 192.168.32.108 fY4yznpUZ48
|
08 192.168.32.108 fY4yznpUZ48
|
||||||
09 192.168.32.109 YlgGCyjo9bY
|
09 192.168.32.109 YlgGCyjo9bY
|
||||||
10 192.168.32.110 GcTnFsp1mHI
|
10 192.168.32.110 GcTnFsp1mHI
|
||||||
11 192.168.32.111 6z88m9oEZio
|
# 11 192.168.32.111 6z88m9oEZio
|
||||||
12 192.168.32.112 EggJqL2kWkA
|
# 12 192.168.32.112 EggJqL2kWkA
|
||||||
13 192.168.32.113 O11eckHFdVE
|
# 13 192.168.32.113 O11eckHFdVE
|
||||||
14 192.168.32.114 reI0SecUEhI
|
# 14 192.168.32.114 reI0SecUEhI
|
||||||
15 192.168.32.115 crozxT8mA44
|
# 15 192.168.32.115 crozxT8mA44
|
||||||
16 192.168.32.116 0nP4VZsvr2Q
|
# 16 192.168.32.116 0nP4VZsvr2Q
|
||||||
17 192.168.32.117 Gm2gNqPGzLA
|
# 17 192.168.32.117 Gm2gNqPGzLA
|
||||||
19 192.168.32.119 6tpukvRVugU
|
# 19 192.168.32.119 6tpukvRVugU
|
||||||
x20 192.168.32.120 rwLYnKUNd1M old 04, spare/retired
|
# x20 192.168.32.120 rwLYnKUNd1M old 04, spare/retired
|
||||||
|
|||||||
6
dist/main/file_handlers.js
vendored
6
dist/main/file_handlers.js
vendored
@@ -174,8 +174,10 @@ function registerFileHandlers() {
|
|||||||
tell application "Microsoft PowerPoint"
|
tell application "Microsoft PowerPoint"
|
||||||
activate
|
activate
|
||||||
open (POSIX file "${target}")
|
open (POSIX file "${target}")
|
||||||
delay 1
|
delay 3
|
||||||
run slide show of active presentation
|
end tell
|
||||||
|
tell application "System Events"
|
||||||
|
keystroke return using command down
|
||||||
end tell
|
end tell
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
2
dist/main/file_handlers.js.map
vendored
2
dist/main/file_handlers.js.map
vendored
File diff suppressed because one or more lines are too long
@@ -21,7 +21,7 @@ export function registerFileHandlers() {
|
|||||||
|
|
||||||
ipcMain.handle('native:check-cache', async (event, { cache_root, hash, hash_prefix_length = 2, verify_hash = false }) => {
|
ipcMain.handle('native:check-cache', async (event, { cache_root, hash, hash_prefix_length = 2, verify_hash = false }) => {
|
||||||
const full_path = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
|
const full_path = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
|
||||||
|
|
||||||
if (!fs.existsSync(full_path)) return false;
|
if (!fs.existsSync(full_path)) return false;
|
||||||
|
|
||||||
if (verify_hash) {
|
if (verify_hash) {
|
||||||
@@ -42,7 +42,7 @@ export function registerFileHandlers() {
|
|||||||
const tmp_path = `${full_path}.tmp`;
|
const tmp_path = `${full_path}.tmp`;
|
||||||
|
|
||||||
if (endpoints_in_progress.includes(url)) return { success: true, status: 'in_progress' };
|
if (endpoints_in_progress.includes(url)) return { success: true, status: 'in_progress' };
|
||||||
|
|
||||||
// 1. If final file exists, skip
|
// 1. If final file exists, skip
|
||||||
if (fs.existsSync(full_path)) return { success: true, path: full_path, status: 'exists' };
|
if (fs.existsSync(full_path)) return { success: true, path: full_path, status: 'exists' };
|
||||||
|
|
||||||
@@ -106,14 +106,14 @@ export function registerFileHandlers() {
|
|||||||
const source = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
|
const source = get_organized_hashed_path(cache_root, hash, hash_prefix_length);
|
||||||
const expanded_temp = expandPath(temp_root);
|
const expanded_temp = expandPath(temp_root);
|
||||||
const target = path.join(expanded_temp, filename);
|
const target = path.join(expanded_temp, filename);
|
||||||
|
|
||||||
console.log(`Native: Launching from Cache -> ${filename}`);
|
console.log(`Native: Launching from Cache -> ${filename}`);
|
||||||
|
|
||||||
if (!fs.existsSync(expanded_temp)) fs.mkdirSync(expanded_temp, { recursive: true });
|
if (!fs.existsSync(expanded_temp)) fs.mkdirSync(expanded_temp, { recursive: true });
|
||||||
|
|
||||||
// 1. Copy the file to temp folder with original name
|
// 1. Copy the file to temp folder with original name
|
||||||
fs.copyFileSync(source, target);
|
fs.copyFileSync(source, target);
|
||||||
|
|
||||||
// 2. Determine file type
|
// 2. Determine file type
|
||||||
const ext = path.extname(filename).toLowerCase().replace('.', '');
|
const ext = path.extname(filename).toLowerCase().replace('.', '');
|
||||||
const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);
|
const is_pres = ['pptx', 'ppt', 'key', 'pdf', 'odp'].includes(ext);
|
||||||
@@ -146,8 +146,10 @@ export function registerFileHandlers() {
|
|||||||
tell application "Microsoft PowerPoint"
|
tell application "Microsoft PowerPoint"
|
||||||
activate
|
activate
|
||||||
open (POSIX file "${target}")
|
open (POSIX file "${target}")
|
||||||
delay 1
|
delay 3
|
||||||
run slide show of active presentation
|
end tell
|
||||||
|
tell application "System Events"
|
||||||
|
keystroke return using command down
|
||||||
end tell
|
end tell
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user