Initial commit: SMF2290 studie-app for eksamen vår 2026
Komplett pensumstudie-app med: - 120 flashcards, 49 quiz-spørsmål, 16 eksamenstrener-oppgaver - Sammendrag av alle 12 forelesninger - tl;dr-side for siste-minutts pugging - Søk gjennom hele pensumet - Dark/light mode, mobile-vennlig Cross-platform launchere (Start.sh + Start.bat) med auto-detect og auto-install av HTTP-server. PowerShell-fallback for Windows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
253
Start.sh
Executable file
253
Start.sh
Executable file
@@ -0,0 +1,253 @@
|
||||
#!/usr/bin/env bash
|
||||
# =====================================================================
|
||||
# SMF2290 Pensum — Start.sh
|
||||
# Universal launcher: setter opp alt som trengs og starter studie-appen.
|
||||
# Fungerer på Linux, macOS, og WSL/Git-Bash på Windows.
|
||||
# =====================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# --- Resolve script directory (works with symlinks too) -----------
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
APP_DIR="$SCRIPT_DIR/app"
|
||||
VENDOR_DIR="$APP_DIR/vendor"
|
||||
DEFAULT_PORT=8765
|
||||
|
||||
# --- ANSI colours --------------------------------------------------
|
||||
if [ -t 1 ] && command -v tput >/dev/null 2>&1; then
|
||||
BOLD="$(tput bold)"; DIM="$(tput dim)"; RESET="$(tput sgr0)"
|
||||
RED="$(tput setaf 1)"; GREEN="$(tput setaf 2)"; YELLOW="$(tput setaf 3)"
|
||||
BLUE="$(tput setaf 4)"; ORANGE="$(tput setaf 208 2>/dev/null || tput setaf 3)"
|
||||
else
|
||||
BOLD=""; DIM=""; RESET=""; RED=""; GREEN=""; YELLOW=""; BLUE=""; ORANGE=""
|
||||
fi
|
||||
|
||||
say() { printf "%s\n" "$*"; }
|
||||
info() { printf " ${BLUE}▸${RESET} %s\n" "$*"; }
|
||||
ok() { printf " ${GREEN}✓${RESET} %s\n" "$*"; }
|
||||
warn() { printf " ${YELLOW}!${RESET} %s\n" "$*"; }
|
||||
err() { printf " ${RED}✗${RESET} %s\n" "$*"; }
|
||||
|
||||
# --- Banner --------------------------------------------------------
|
||||
banner() {
|
||||
printf "\n"
|
||||
printf " ${ORANGE}${BOLD}SMF · 2290${RESET} ${DIM}Etikk, bærekraft og samfunnsansvar${RESET}\n"
|
||||
printf " ${BOLD}${BOLD}Pensum${RESET} ${DIM}studie-app · v1.0${RESET}\n"
|
||||
printf "\n"
|
||||
}
|
||||
banner
|
||||
|
||||
# --- Sanity check --------------------------------------------------
|
||||
if [ ! -d "$APP_DIR" ]; then
|
||||
err "Fant ikke app-mappen: $APP_DIR"
|
||||
err "Kjør Start.sh fra SMF-prosjektmappen."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- OS detection --------------------------------------------------
|
||||
OS_NAME="$(uname -s 2>/dev/null || echo unknown)"
|
||||
case "$OS_NAME" in
|
||||
Linux*) PLATFORM="linux" ;;
|
||||
Darwin*) PLATFORM="macos" ;;
|
||||
MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
|
||||
*) PLATFORM="unknown" ;;
|
||||
esac
|
||||
info "Plattform: ${BOLD}$PLATFORM${RESET}"
|
||||
|
||||
# --- Detect / install HTTP server ---------------------------------
|
||||
SERVER_CMD=""
|
||||
SERVER_NAME=""
|
||||
|
||||
find_server() {
|
||||
if command -v python3 >/dev/null 2>&1; then
|
||||
SERVER_CMD="python3 -m http.server PORT --bind 127.0.0.1"
|
||||
SERVER_NAME="Python 3 ($(python3 --version 2>&1 | awk '{print $2}'))"
|
||||
return 0
|
||||
fi
|
||||
if command -v python >/dev/null 2>&1 && python --version 2>&1 | grep -q "Python 3"; then
|
||||
SERVER_CMD="python -m http.server PORT --bind 127.0.0.1"
|
||||
SERVER_NAME="Python 3 ($(python --version 2>&1 | awk '{print $2}'))"
|
||||
return 0
|
||||
fi
|
||||
if command -v php >/dev/null 2>&1; then
|
||||
SERVER_CMD="php -S 127.0.0.1:PORT -t ."
|
||||
SERVER_NAME="PHP $(php --version 2>&1 | head -1 | awk '{print $2}')"
|
||||
return 0
|
||||
fi
|
||||
if command -v ruby >/dev/null 2>&1; then
|
||||
SERVER_CMD="ruby -run -e httpd . --port=PORT --bind-address=127.0.0.1"
|
||||
SERVER_NAME="Ruby $(ruby --version 2>&1 | awk '{print $2}')"
|
||||
return 0
|
||||
fi
|
||||
if command -v node >/dev/null 2>&1 && command -v npx >/dev/null 2>&1; then
|
||||
SERVER_CMD="npx --yes http-server -p PORT -a 127.0.0.1 --silent"
|
||||
SERVER_NAME="Node.js $(node --version 2>&1)"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
try_install_python() {
|
||||
warn "Ingen webserver funnet. Forsøker å installere Python 3 …"
|
||||
local installed=0
|
||||
if command -v apt-get >/dev/null 2>&1; then
|
||||
info "Bruker apt (Debian/Ubuntu)"
|
||||
if sudo -n true 2>/dev/null || sudo -v; then
|
||||
sudo apt-get update -y && sudo apt-get install -y python3 && installed=1
|
||||
fi
|
||||
elif command -v dnf >/dev/null 2>&1; then
|
||||
info "Bruker dnf (Fedora/RHEL)"
|
||||
sudo dnf install -y python3 && installed=1
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
info "Bruker yum"
|
||||
sudo yum install -y python3 && installed=1
|
||||
elif command -v pacman >/dev/null 2>&1; then
|
||||
info "Bruker pacman (Arch)"
|
||||
sudo pacman -Sy --noconfirm python && installed=1
|
||||
elif command -v zypper >/dev/null 2>&1; then
|
||||
info "Bruker zypper (openSUSE)"
|
||||
sudo zypper install -y python3 && installed=1
|
||||
elif command -v apk >/dev/null 2>&1; then
|
||||
info "Bruker apk (Alpine)"
|
||||
sudo apk add python3 && installed=1
|
||||
elif command -v brew >/dev/null 2>&1; then
|
||||
info "Bruker Homebrew (macOS)"
|
||||
brew install python3 && installed=1
|
||||
elif [ "$PLATFORM" = "macos" ]; then
|
||||
warn "Homebrew finnes ikke. Installerer Homebrew først …"
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" \
|
||||
&& brew install python3 && installed=1
|
||||
fi
|
||||
[ $installed -eq 1 ]
|
||||
}
|
||||
|
||||
info "Søker etter HTTP-server …"
|
||||
if find_server; then
|
||||
ok "Server-runtime: ${BOLD}$SERVER_NAME${RESET}"
|
||||
else
|
||||
if try_install_python && find_server; then
|
||||
ok "Server-runtime: ${BOLD}$SERVER_NAME${RESET} (nylig installert)"
|
||||
else
|
||||
err "Klarte ikke installere en webserver automatisk."
|
||||
say ""
|
||||
say " Installer ${BOLD}én av disse${RESET} manuelt og prøv igjen:"
|
||||
say " • Python 3: https://www.python.org/downloads/"
|
||||
say " • Node.js: https://nodejs.org/"
|
||||
say " • PHP eller Ruby via pakkesystemet ditt"
|
||||
say ""
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# --- Verify marked.js (markdown renderer) -------------------------
|
||||
if [ ! -s "$VENDOR_DIR/marked.min.js" ]; then
|
||||
warn "marked.min.js mangler — laster ned …"
|
||||
mkdir -p "$VENDOR_DIR"
|
||||
if command -v curl >/dev/null 2>&1; then
|
||||
curl -fsSL https://cdn.jsdelivr.net/npm/marked/marked.min.js -o "$VENDOR_DIR/marked.min.js" \
|
||||
&& ok "marked.js lastet ned" \
|
||||
|| { err "Klarte ikke laste ned marked.js. Trenger internett ved første kjøring."; exit 1; }
|
||||
elif command -v wget >/dev/null 2>&1; then
|
||||
wget -q https://cdn.jsdelivr.net/npm/marked/marked.min.js -O "$VENDOR_DIR/marked.min.js" \
|
||||
&& ok "marked.js lastet ned" \
|
||||
|| { err "Klarte ikke laste ned marked.js."; exit 1; }
|
||||
else
|
||||
err "Hverken curl eller wget funnet. Installer en av dem og kjør Start.sh igjen."
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
ok "marked.js OK ($(wc -c < "$VENDOR_DIR/marked.min.js") bytes)"
|
||||
fi
|
||||
|
||||
# --- Sanity-sjekk dataene ----------------------------------------
|
||||
required_files=(
|
||||
"index.html"
|
||||
"css/style.css"
|
||||
"js/app.js"
|
||||
"data/flashcards.json"
|
||||
"data/quiz.json"
|
||||
"data/exam.json"
|
||||
"notes/uke17-eksamen.md"
|
||||
)
|
||||
missing=0
|
||||
for f in "${required_files[@]}"; do
|
||||
if [ ! -e "$APP_DIR/$f" ] && [ ! -L "$APP_DIR/$f" ]; then
|
||||
err "Mangler: app/$f"
|
||||
missing=$((missing + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
# Notes-mappen er en symlink — sjekk at den peker rett
|
||||
if [ -L "$APP_DIR/notes" ] && [ ! -e "$APP_DIR/notes" ]; then
|
||||
warn "notes-symlink er ødelagt — gjenoppretter …"
|
||||
rm -f "$APP_DIR/notes"
|
||||
fi
|
||||
if [ ! -d "$APP_DIR/notes" ]; then
|
||||
if [ -d "$SCRIPT_DIR/notes" ]; then
|
||||
ln -sfn "../notes" "$APP_DIR/notes"
|
||||
ok "Symlink notes/ gjenopprettet"
|
||||
else
|
||||
err "Fant ikke notes/-mappen i prosjektet"
|
||||
missing=$((missing + 1))
|
||||
fi
|
||||
fi
|
||||
[ $missing -eq 0 ] && ok "Alle nødvendige filer på plass"
|
||||
|
||||
# --- Pick a free port --------------------------------------------
|
||||
port_free() {
|
||||
local p="$1"
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
! lsof -i :"$p" -sTCP:LISTEN >/dev/null 2>&1
|
||||
elif command -v ss >/dev/null 2>&1; then
|
||||
! ss -ltn 2>/dev/null | awk '{print $4}' | grep -q ":$p$"
|
||||
elif command -v netstat >/dev/null 2>&1; then
|
||||
! netstat -ltn 2>/dev/null | awk '{print $4}' | grep -q ":$p$"
|
||||
else
|
||||
# No tool — assume free, the server will error out if not
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
PORT="$DEFAULT_PORT"
|
||||
while ! port_free "$PORT"; do
|
||||
warn "Port $PORT er opptatt — prøver $((PORT + 1))"
|
||||
PORT=$((PORT + 1))
|
||||
if [ "$PORT" -gt 8800 ]; then
|
||||
err "Fant ingen ledig port i 8765–8800. Lukk noen prosesser og prøv igjen."
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
URL="http://localhost:$PORT"
|
||||
SERVER_CMD="${SERVER_CMD//PORT/$PORT}"
|
||||
|
||||
# --- Auto-open browser -------------------------------------------
|
||||
open_browser() {
|
||||
( sleep 1.5
|
||||
if command -v xdg-open >/dev/null 2>&1; then
|
||||
xdg-open "$URL" >/dev/null 2>&1 &
|
||||
elif command -v open >/dev/null 2>&1; then
|
||||
open "$URL" >/dev/null 2>&1 &
|
||||
elif command -v start >/dev/null 2>&1; then
|
||||
start "$URL" >/dev/null 2>&1 &
|
||||
fi
|
||||
) &
|
||||
}
|
||||
|
||||
# --- Banner og start ----------------------------------------------
|
||||
printf "\n"
|
||||
printf " ${BOLD}┌──────────────────────────────────────────────┐${RESET}\n"
|
||||
printf " ${BOLD}│${RESET} ${ORANGE}${BOLD}SMF2290${RESET} · Pensum ${BOLD}│${RESET}\n"
|
||||
printf " ${BOLD}│${RESET} ${BOLD}│${RESET}\n"
|
||||
printf " ${BOLD}│${RESET} ${GREEN}→ %-42s${RESET}${BOLD}│${RESET}\n" "$URL"
|
||||
printf " ${BOLD}│${RESET} ${BOLD}│${RESET}\n"
|
||||
SHORT_NAME="${SERVER_NAME:0:36}"
|
||||
printf " ${BOLD}│${RESET} ${DIM}Server: %-38s${RESET}${BOLD}│${RESET}\n" "$SHORT_NAME"
|
||||
printf " ${BOLD}│${RESET} ${DIM}Trykk Ctrl+C for å stoppe${RESET} ${BOLD}│${RESET}\n"
|
||||
printf " ${BOLD}└──────────────────────────────────────────────┘${RESET}\n\n"
|
||||
|
||||
open_browser
|
||||
|
||||
cd "$APP_DIR"
|
||||
# shellcheck disable=SC2086
|
||||
exec $SERVER_CMD
|
||||
Reference in New Issue
Block a user