#!/bin/bash # ───────────────────────────────────────────────────────────── # Creates "YouTube Summarizer.app" — a proper macOS app bundle # that you can put in your Dock, Desktop, or Applications folder. # # Usage: Run this once from the project folder: # chmod +x create-app.sh && ./create-app.sh # ───────────────────────────────────────────────────────────── PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" APP_NAME="YouTube Summarizer" APP_PATH="$PROJECT_DIR/$APP_NAME.app" echo "" echo "Creating $APP_NAME.app..." echo "" # ── Build the .app bundle structure ────────────────────────── rm -rf "$APP_PATH" mkdir -p "$APP_PATH/Contents/MacOS" mkdir -p "$APP_PATH/Contents/Resources" # ── Create the launcher script ─────────────────────────────── cat > "$APP_PATH/Contents/MacOS/launcher" << 'LAUNCHER' #!/bin/bash # Resolve the real project directory (the .app lives inside it) APP_DIR="$(cd "$(dirname "$0")/../../.." && pwd)" # If the app has been moved (e.g. to /Applications), check for a saved path SAVED_PATH="$HOME/.config/youtube-summarizer/project-path" if [ ! -f "$APP_DIR/server/index.js" ]; then if [ -f "$SAVED_PATH" ]; then APP_DIR="$(cat "$SAVED_PATH")" else # Ask the user to locate the project folder APP_DIR=$(osascript -e 'POSIX path of (choose folder with prompt "Locate your YouTube Summarizer project folder:")') APP_DIR="${APP_DIR%/}" if [ -z "$APP_DIR" ] || [ ! -f "$APP_DIR/server/index.js" ]; then osascript -e 'display alert "YouTube Summarizer" message "Could not find the project folder. Make sure server/index.js exists." as critical' exit 1 fi mkdir -p "$(dirname "$SAVED_PATH")" echo "$APP_DIR" > "$SAVED_PATH" fi fi cd "$APP_DIR" # Add common Homebrew paths (node, yt-dlp) export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH" # Check for Node.js if ! command -v node &> /dev/null; then osascript -e 'display alert "YouTube Summarizer" message "Node.js is not installed. Install it with: brew install node" as critical' exit 1 fi # Check for yt-dlp if ! command -v yt-dlp &> /dev/null; then if command -v brew &> /dev/null; then brew install yt-dlp 2>&1 else osascript -e 'display alert "YouTube Summarizer" message "yt-dlp is not installed. Install it with: brew install yt-dlp" as critical' exit 1 fi fi # Install npm dependencies if needed if [ ! -d "server/node_modules" ]; then cd server && npm install && cd .. fi # Ask user: Home or Traveling? ICON_PATH="$APP_DIR/assets/icon.png" NETWORK_CHOICE=$(osascript -e " set iconFile to POSIX file \"$ICON_PATH\" set theChoice to button returned of (display dialog \"Where are you right now?\" & return & return & \"Home — allows your phone and other devices on your Wi-Fi to use the app.\" & return & return & \"Traveling — locks access to just this laptop for safety on public Wi-Fi.\" buttons {\"Traveling\", \"Home\"} default button \"Traveling\" with title \"YouTube Summarizer\" with icon iconFile) return theChoice " 2>/dev/null) # Default to traveling (safe) if dialog was cancelled if [ "$NETWORK_CHOICE" = "Home" ]; then export LAN_MODE=true else export LAN_MODE=false fi # Kill any existing instance on port 3001 lsof -ti:3001 | xargs kill -9 2>/dev/null sleep 0.3 # Start the server cd server node index.js & SERVER_PID=$! cd .. # Wait for server to be ready (up to 10 seconds) for i in {1..20}; do if curl -s http://localhost:3001/api/health > /dev/null 2>&1; then break fi sleep 0.5 done # Open browser open http://localhost:3001 # Keep alive — when the app is quit, stop the server trap "kill $SERVER_PID 2>/dev/null; exit 0" INT TERM wait $SERVER_PID LAUNCHER chmod +x "$APP_PATH/Contents/MacOS/launcher" # ── Create Info.plist ──────────────────────────────────────── cat > "$APP_PATH/Contents/Info.plist" << PLIST CFBundleExecutable launcher CFBundleName YouTube Summarizer CFBundleIdentifier com.local.youtube-summarizer CFBundleVersion 1.0 CFBundlePackageType APPL CFBundleIconFile AppIcon LSUIElement PLIST # ── Create the app icon from the pre-made PNG ─────────────── ICON_PNG="$PROJECT_DIR/assets/icon.png" ICON_DIR="$APP_PATH/Contents/Resources" if [ -f "$ICON_PNG" ]; then echo "Building app icon..." # Create iconset with all required sizes using sips (built into macOS) ICONSET="$ICON_DIR/AppIcon.iconset" mkdir -p "$ICONSET" for size in 16 32 64 128 256 512; do sips -z $size $size "$ICON_PNG" --out "$ICONSET/icon_${size}x${size}.png" > /dev/null 2>&1 done # @2x variants for size in 16 32 128 256 512; do double=$((size * 2)) sips -z $double $double "$ICON_PNG" --out "$ICONSET/icon_${size}x${size}@2x.png" > /dev/null 2>&1 done # Convert iconset → .icns using iconutil (built into macOS) iconutil -c icns "$ICONSET" -o "$ICON_DIR/AppIcon.icns" 2>/dev/null # Clean up the iconset folder rm -rf "$ICONSET" if [ -f "$ICON_DIR/AppIcon.icns" ]; then echo " Icon created successfully." else echo " Warning: Could not create .icns icon. The app will use a generic icon." fi else echo " Warning: assets/icon.png not found. The app will use a generic icon." fi # ── Remove quarantine so macOS doesn't block it ───────────── xattr -d com.apple.quarantine "$APP_PATH" 2>/dev/null # ── Done! ──────────────────────────────────────────────────── echo "" echo "============================================" echo " Created: $APP_NAME.app" echo "============================================" echo "" echo "You can now:" echo " 1. Double-click it to launch the app" echo " 2. Drag it to your Dock for quick access" echo " 3. Move it to /Applications if you prefer" echo "" echo "If you move it outside this folder, it will" echo "ask you to locate the project folder once." echo "" echo "Done!" echo ""