195 lines
6.7 KiB
Bash
Executable File
195 lines
6.7 KiB
Bash
Executable File
#!/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
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>CFBundleExecutable</key>
|
|
<string>launcher</string>
|
|
<key>CFBundleName</key>
|
|
<string>YouTube Summarizer</string>
|
|
<key>CFBundleIdentifier</key>
|
|
<string>com.local.youtube-summarizer</string>
|
|
<key>CFBundleVersion</key>
|
|
<string>1.0</string>
|
|
<key>CFBundlePackageType</key>
|
|
<string>APPL</string>
|
|
<key>CFBundleIconFile</key>
|
|
<string>AppIcon</string>
|
|
<key>LSUIElement</key>
|
|
<true/>
|
|
</dict>
|
|
</plist>
|
|
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 ""
|