1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-15 02:55:10 +00:00

fix: improve CI stability and Bluetooth audio detection

This commit is contained in:
Tw93
2025-12-30 16:27:52 +08:00
parent 389cae21c9
commit 41ce597f02
3 changed files with 224 additions and 131 deletions

View File

@@ -182,32 +182,42 @@ normalize_paths_for_cleanup() {
local normalized="${path%/}" local normalized="${path%/}"
[[ -z "$normalized" ]] && normalized="$path" [[ -z "$normalized" ]] && normalized="$path"
local found=false local found=false
if [[ ${#unique_paths[@]} -gt 0 ]]; then
for existing in "${unique_paths[@]}"; do for existing in "${unique_paths[@]}"; do
if [[ "$existing" == "$normalized" ]]; then if [[ "$existing" == "$normalized" ]]; then
found=true found=true
break break
fi fi
done done
fi
[[ "$found" == "true" ]] || unique_paths+=("$normalized") [[ "$found" == "true" ]] || unique_paths+=("$normalized")
done done
local sorted_paths local sorted_paths
if [[ ${#unique_paths[@]} -gt 0 ]]; then
sorted_paths=$(printf '%s\n' "${unique_paths[@]}" | awk '{print length "|" $0}' | LC_ALL=C sort -n | cut -d'|' -f2-) sorted_paths=$(printf '%s\n' "${unique_paths[@]}" | awk '{print length "|" $0}' | LC_ALL=C sort -n | cut -d'|' -f2-)
else
sorted_paths=""
fi
local -a result_paths=() local -a result_paths=()
while IFS= read -r path; do while IFS= read -r path; do
[[ -z "$path" ]] && continue [[ -z "$path" ]] && continue
local is_child=false local is_child=false
if [[ ${#result_paths[@]} -gt 0 ]]; then
for kept in "${result_paths[@]}"; do for kept in "${result_paths[@]}"; do
if [[ "$path" == "$kept" || "$path" == "$kept"/* ]]; then if [[ "$path" == "$kept" || "$path" == "$kept"/* ]]; then
is_child=true is_child=true
break break
fi fi
done done
fi
[[ "$is_child" == "true" ]] || result_paths+=("$path") [[ "$is_child" == "true" ]] || result_paths+=("$path")
done <<< "$sorted_paths" done <<< "$sorted_paths"
if [[ ${#result_paths[@]} -gt 0 ]]; then
printf '%s\n' "${result_paths[@]}" printf '%s\n' "${result_paths[@]}"
fi
} }
get_cleanup_path_size_kb() { get_cleanup_path_size_kb() {
@@ -307,7 +317,12 @@ safe_clean() {
while IFS= read -r path; do while IFS= read -r path; do
[[ -n "$path" ]] && normalized_paths+=("$path") [[ -n "$path" ]] && normalized_paths+=("$path")
done < <(normalize_paths_for_cleanup "${existing_paths[@]}") done < <(normalize_paths_for_cleanup "${existing_paths[@]}")
if [[ ${#normalized_paths[@]} -gt 0 ]]; then
existing_paths=("${normalized_paths[@]}") existing_paths=("${normalized_paths[@]}")
else
existing_paths=()
fi
fi fi
# Only show spinner if we have enough items to justify it (>10 items) # Only show spinner if we have enough items to justify it (>10 items)
@@ -330,6 +345,7 @@ safe_clean() {
local last_progress_update=$(date +%s) local last_progress_update=$(date +%s)
local total_paths=${#existing_paths[@]} local total_paths=${#existing_paths[@]}
if [[ ${#existing_paths[@]} -gt 0 ]]; then
for path in "${existing_paths[@]}"; do for path in "${existing_paths[@]}"; do
( (
local size local size
@@ -361,7 +377,9 @@ safe_clean() {
fi fi
fi fi
done done
fi
if [[ ${#pids[@]} -gt 0 ]]; then
for pid in "${pids[@]}"; do for pid in "${pids[@]}"; do
wait "$pid" 2> /dev/null || true wait "$pid" 2> /dev/null || true
((completed++)) ((completed++))
@@ -371,9 +389,11 @@ safe_clean() {
update_progress_if_needed "$completed" "$total_paths" last_progress_update 2 || true update_progress_if_needed "$completed" "$total_paths" last_progress_update 2 || true
fi fi
done done
fi
# Read results using same index # Read results using same index
idx=0 idx=0
if [[ ${#existing_paths[@]} -gt 0 ]]; then
for path in "${existing_paths[@]}"; do for path in "${existing_paths[@]}"; do
local result_file="$temp_dir/result_${idx}" local result_file="$temp_dir/result_${idx}"
if [[ -f "$result_file" ]]; then if [[ -f "$result_file" ]]; then
@@ -416,10 +436,12 @@ safe_clean() {
fi fi
((idx++)) ((idx++))
done done
fi
# Temp dir will be auto-cleaned by cleanup_temp_files # Temp dir will be auto-cleaned by cleanup_temp_files
else else
local idx=0 local idx=0
if [[ ${#existing_paths[@]} -gt 0 ]]; then
for path in "${existing_paths[@]}"; do for path in "${existing_paths[@]}"; do
local size_kb local size_kb
size_kb=$(get_cleanup_path_size_kb "$path") size_kb=$(get_cleanup_path_size_kb "$path")
@@ -458,6 +480,7 @@ safe_clean() {
((idx++)) ((idx++))
done done
fi fi
fi
if [[ "$show_spinner" == "true" ]]; then if [[ "$show_spinner" == "true" ]]; then
stop_section_spinner stop_section_spinner
@@ -488,6 +511,7 @@ safe_clean() {
local paths_temp=$(create_temp_file) local paths_temp=$(create_temp_file)
idx=0 idx=0
if [[ ${#existing_paths[@]} -gt 0 ]]; then
for path in "${existing_paths[@]}"; do for path in "${existing_paths[@]}"; do
local size=0 local size=0
@@ -505,6 +529,7 @@ safe_clean() {
echo "$(dirname "$path")|$size|$path" >> "$paths_temp" echo "$(dirname "$path")|$size|$path" >> "$paths_temp"
((idx++)) ((idx++))
done done
fi
# Group and export paths # Group and export paths
if [[ -f "$paths_temp" && -s "$paths_temp" ]]; then if [[ -f "$paths_temp" && -s "$paths_temp" ]]; then

View File

@@ -506,7 +506,9 @@ opt_disk_permissions_repair() {
# Bluetooth module reset # Bluetooth module reset
# Resets Bluetooth daemon to fix connectivity issues # Resets Bluetooth daemon to fix connectivity issues
# Only runs if no Bluetooth audio is playing # Intelligently detects Bluetooth audio usage:
# 1. Checks if default audio output is Bluetooth (precise)
# 2. Falls back to Bluetooth + media app detection (compatibility)
opt_bluetooth_reset() { opt_bluetooth_reset() {
if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then if [[ "${MOLE_DRY_RUN:-0}" != "1" ]]; then
if has_bluetooth_hid_connected; then if has_bluetooth_hid_connected; then
@@ -517,10 +519,24 @@ opt_bluetooth_reset() {
# Check if any audio is playing through Bluetooth # Check if any audio is playing through Bluetooth
local bt_audio_active=false local bt_audio_active=false
# Check system audio output # Method 1: Check if default audio output is Bluetooth (precise)
local audio_info
audio_info=$(system_profiler SPAudioDataType 2> /dev/null || echo "")
# Extract default output device information
local default_output
default_output=$(echo "$audio_info" | awk '/Default Output Device: Yes/,/^$/' 2> /dev/null || echo "")
# Check if transport type is Bluetooth
if echo "$default_output" | grep -qi "Transport:.*Bluetooth"; then
bt_audio_active=true
fi
# Method 2: Fallback - Bluetooth connected + media apps running (compatibility)
if [[ "$bt_audio_active" == "false" ]]; then
if system_profiler SPBluetoothDataType 2> /dev/null | grep -q "Connected: Yes"; then if system_profiler SPBluetoothDataType 2> /dev/null | grep -q "Connected: Yes"; then
# Check if any audio/video apps are running that might be using Bluetooth # Extended media apps list for broader coverage
local -a media_apps=("Music" "Spotify" "VLC" "QuickTime Player" "TV" "Podcasts") local -a media_apps=("Music" "Spotify" "VLC" "QuickTime Player" "TV" "Podcasts" "Safari" "Google Chrome" "Chrome" "Firefox" "Arc" "IINA" "mpv")
for app in "${media_apps[@]}"; do for app in "${media_apps[@]}"; do
if pgrep -x "$app" > /dev/null 2>&1; then if pgrep -x "$app" > /dev/null 2>&1; then
bt_audio_active=true bt_audio_active=true
@@ -528,6 +544,7 @@ opt_bluetooth_reset() {
fi fi
done done
fi fi
fi
if [[ "$bt_audio_active" == "true" ]]; then if [[ "$bt_audio_active" == "true" ]]; then
opt_msg "Bluetooth already optimal" opt_msg "Bluetooth already optimal"

View File

@@ -956,6 +956,57 @@ EOF
[[ "$output" == *"Bluetooth already optimal"* ]] [[ "$output" == *"Bluetooth already optimal"* ]]
} }
@test "opt_bluetooth_reset skips when Bluetooth audio output is active" {
run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF'
set -euo pipefail
source "$PROJECT_ROOT/lib/core/common.sh"
source "$PROJECT_ROOT/lib/optimize/tasks.sh"
# Mock system_profiler to return Bluetooth audio as default output (Method 1)
system_profiler() {
if [[ "$1" == "SPAudioDataType" ]]; then
cat << 'AUDIO_OUT'
Audio:
Devices:
AirPods Pro:
Default Output Device: Yes
Manufacturer: Apple Inc.
Output Channels: 2
Transport: Bluetooth
Output Source: AirPods Pro
AUDIO_OUT
return 0
elif [[ "$1" == "SPBluetoothDataType" ]]; then
echo "Bluetooth:"
return 0
fi
return 1
}
export -f system_profiler
# Mock awk to process audio output
awk() {
if [[ "${*}" == *"Default Output Device"* ]]; then
cat << 'AWK_OUT'
Default Output Device: Yes
Manufacturer: Apple Inc.
Output Channels: 2
Transport: Bluetooth
Output Source: AirPods Pro
AWK_OUT
return 0
fi
command awk "$@"
}
export -f awk
opt_bluetooth_reset
EOF
[ "$status" -eq 0 ]
[[ "$output" == *"Bluetooth already optimal"* ]]
}
@test "opt_bluetooth_reset restarts when safe" { @test "opt_bluetooth_reset restarts when safe" {
run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF'
set -euo pipefail set -euo pipefail