media-libraries.sh 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #!/usr/bin/env bash
  2. # mac-ops :: media-libraries.sh
  3. # Audit Photos, Music, TV, and other media libraries: sizes, locations,
  4. # integrity status, and the sync daemons that manage them.
  5. set -u
  6. while [[ $# -gt 0 ]]; do
  7. case "$1" in
  8. --help|-h)
  9. cat <<EOF
  10. Usage: $0 [options]
  11. --json, --redact, --quiet, --verbose
  12. Reports:
  13. 1. Photos library locations + size
  14. 2. Music / TV library
  15. 3. Pro app libraries (Final Cut, Logic, iMovie)
  16. 4. iCloud Drive / Mobile Documents size
  17. 5. Photos / Music sync daemons (photolibraryd, cloudphotod, photoanalysisd,
  18. amsondemandinstalld, cloudd, bird) — CPU + memory
  19. 6. Suspended sync state (frequent silent cause of "Photos won't sync")
  20. These libraries can be 10s-100s of GB and show as "Other" in About This Mac.
  21. EOF
  22. exit 0 ;;
  23. *) shift ;;
  24. esac
  25. done
  26. source "$(dirname "$0")/_lib/common.sh"
  27. parse_common_flags "$@"
  28. maybe_filter_self "$@"
  29. # ----------------------------------------------------------------------------
  30. section "1. PHOTOS LIBRARIES"
  31. # ----------------------------------------------------------------------------
  32. # Default location:
  33. default_photos="$HOME/Pictures/Photos Library.photoslibrary"
  34. # Find any .photoslibrary anywhere reasonable
  35. photo_libs=$(find "$HOME/Pictures" /Users/Shared "$HOME/Documents" -maxdepth 2 -name "*.photoslibrary" -type d 2>/dev/null | head -5)
  36. # Also check external volumes if mounted
  37. ext_photo_libs=$(find /Volumes -maxdepth 3 -name "*.photoslibrary" -type d 2>/dev/null | head -5)
  38. photo_libs="$photo_libs"$'\n'"$ext_photo_libs"
  39. photo_libs=$(echo "$photo_libs" | grep -v '^$')
  40. if [[ -z "$photo_libs" ]]; then
  41. log_info "Photos libraries" "none found"
  42. else
  43. n=$(echo "$photo_libs" | wc -l | tr -d ' ')
  44. log_info "Photos libraries" "$n found"
  45. while IFS= read -r lib; do
  46. [[ -z "$lib" ]] && continue
  47. size=$(du -sh "$lib" 2>/dev/null | awk '{print $1}')
  48. printf " %s = %s\n" "$lib" "${size:-?}"
  49. done <<< "$photo_libs"
  50. fi
  51. # Current Photos system library
  52. sys_photos=$(defaults read com.apple.Photos UserLibrarySelectionMethod 2>/dev/null || echo "")
  53. if [[ -n "$sys_photos" ]]; then
  54. note ""
  55. note " System Photos library: per Photos.app preferences"
  56. fi
  57. # ----------------------------------------------------------------------------
  58. section "2. MUSIC / TV LIBRARIES"
  59. # ----------------------------------------------------------------------------
  60. music_lib="$HOME/Music/Music"
  61. if [[ -d "$music_lib" ]]; then
  62. size=$(du -sh "$music_lib" 2>/dev/null | awk '{print $1}')
  63. log_info "Music library" "${size:-?} ($music_lib)"
  64. fi
  65. # .musiclibrary
  66. musiclibs=$(find "$HOME/Music" -maxdepth 2 -name "*.musiclibrary" -type d 2>/dev/null | head -3)
  67. if [[ -n "$musiclibs" ]]; then
  68. while IFS= read -r lib; do
  69. [[ -z "$lib" ]] && continue
  70. size=$(du -sh "$lib" 2>/dev/null | awk '{print $1}')
  71. note " $lib = ${size:-?}"
  72. done <<< "$musiclibs"
  73. fi
  74. # TV
  75. tv_dir="$HOME/Movies/TV"
  76. if [[ -d "$tv_dir" ]]; then
  77. size=$(du -sh "$tv_dir" 2>/dev/null | awk '{print $1}')
  78. log_info "TV library" "${size:-?} ($tv_dir)"
  79. fi
  80. # ----------------------------------------------------------------------------
  81. section "3. PRO APP LIBRARIES"
  82. # ----------------------------------------------------------------------------
  83. note " Scanning for FCP / Logic / iMovie libraries..."
  84. pro_libs=$(find "$HOME/Movies" "$HOME/Documents" "$HOME/Logic" /Volumes -maxdepth 3 \
  85. \( -name "*.fcpbundle" -o -name "*.logicx" -o -name "*.imovielibrary" -o -name "*.band" \) -type d 2>/dev/null | head -10)
  86. if [[ -z "$pro_libs" ]]; then
  87. log_info "Pro app libraries" "none found in standard locations"
  88. else
  89. n=$(echo "$pro_libs" | wc -l | tr -d ' ')
  90. log_info "Pro app libraries" "$n found"
  91. while IFS= read -r lib; do
  92. [[ -z "$lib" ]] && continue
  93. size=$(du -sh "$lib" 2>/dev/null | awk '{print $1}')
  94. printf " %s = %s\n" "$lib" "${size:-?}"
  95. done <<< "$pro_libs"
  96. fi
  97. # ----------------------------------------------------------------------------
  98. section "4. iCLOUD DRIVE / MOBILE DOCUMENTS"
  99. # ----------------------------------------------------------------------------
  100. icloud="$HOME/Library/Mobile Documents"
  101. if [[ -d "$icloud" ]]; then
  102. size=$(du -sh "$icloud" 2>/dev/null | awk '{print $1}')
  103. log_info "iCloud Drive cache" "${size:-?}"
  104. note " (Subset is downloaded; rest is placeholders. macOS evicts under pressure.)"
  105. fi
  106. # Top iCloud Drive consumers
  107. note ""
  108. note " Top consumers under iCloud Drive (du -sh, may be slow):"
  109. find "$icloud" -maxdepth 2 -type d 2>/dev/null | head -10 | while read -r d; do
  110. [[ "$d" == "$icloud" ]] && continue
  111. size=$(du -sh "$d" 2>/dev/null | awk '{print $1}')
  112. printf " %s = %s\n" "$d" "${size:-?}"
  113. done | sort -k3 -h -r | head -5
  114. # ----------------------------------------------------------------------------
  115. section "5. SYNC DAEMONS — CPU SNAPSHOT"
  116. # ----------------------------------------------------------------------------
  117. note " Process CPU%:"
  118. for proc in photolibraryd cloudphotod photoanalysisd amsondemandinstalld cloudd bird fileproviderd; do
  119. cpu=$(ps -ArcS -o pcpu,comm 2>/dev/null | awk -v p="$proc" '$2==p{print $1; exit}')
  120. cpu="${cpu:-0}"
  121. cpu_int=${cpu%.*}
  122. if [[ "${cpu_int:-0}" -gt 50 ]]; then
  123. log_warn "$proc" "${cpu}% — sustained sync activity"
  124. elif [[ "${cpu_int:-0}" -gt 0 ]]; then
  125. log_info "$proc" "${cpu}%"
  126. fi
  127. done
  128. # ----------------------------------------------------------------------------
  129. section "6. SYNC HEALTH"
  130. # ----------------------------------------------------------------------------
  131. # Check for suspended sync / iCloud sign-out / etc.
  132. icloud_status=$(brctl status 2>/dev/null || true)
  133. if [[ -n "$icloud_status" ]] && echo "$icloud_status" | grep -q "iCloud Drive Disabled"; then
  134. log_warn "iCloud Drive" "disabled"
  135. fi
  136. # Photos cloud status
  137. note ""
  138. note " Recent photolibraryd / cloudphotod errors (24h):"
  139. photo_errs=$(log show --last 24h --style compact \
  140. --predicate 'process == "photolibraryd" OR process == "cloudphotod"' \
  141. 2>/dev/null | grep -iE "(error|fail|fault)" | tail -5)
  142. if [[ -n "$photo_errs" ]]; then
  143. echo "$photo_errs" | sed 's/^/ /'
  144. else
  145. note " (none)"
  146. fi
  147. # ----------------------------------------------------------------------------
  148. emit_summary