From 20a379083469c8be4490b80aa357f3a0f0ed1f65 Mon Sep 17 00:00:00 2001 From: Your Name Date: Tue, 2 Sep 2025 22:51:24 +1200 Subject: [PATCH] test: Remove 42 files --- squashkiwi-streaming/.gitignore | 7 - squashkiwi-streaming/_paths.sh | 14 - squashkiwi-streaming/backup.sh | 11 - .../config/.template_info.env | 16 - .../config/docker-compose.yml | 150 -------- squashkiwi-streaming/config/mediamtx.yml | 47 --- squashkiwi-streaming/config/nginx.conf | 120 ------- .../config/overlay/Dockerfile | 33 -- .../config/overlay/overlay_service.py | 327 ----------------- .../config/overlay/requirements.txt | 3 - squashkiwi-streaming/config/service.env | 49 --- .../config/transcoder/Dockerfile | 15 - .../config/transcoder/transcoder.sh | 34 -- squashkiwi-streaming/config/web/index.html | 329 ------------------ squashkiwi-streaming/config/web/test.html | 165 --------- squashkiwi-streaming/config/web/webrtc.html | 299 ---------------- squashkiwi-streaming/destroy.sh | 15 - squashkiwi-streaming/install.sh | 76 ---- squashkiwi-streaming/logs.sh | 9 - squashkiwi-streaming/ports.sh | 23 -- squashkiwi-streaming/restore.sh | 22 -- squashkiwi-streaming/ssh.sh | 18 - squashkiwi-streaming/start.sh | 37 -- squashkiwi-streaming/status.sh | 33 -- squashkiwi-streaming/stop.sh | 11 - squashkiwi-streaming/test-camera.sh | 89 ----- squashkiwi-streaming/test-substream.sh | 12 - squashkiwi-streaming/uninstall.sh | 11 - squashkiwi/_paths.sh | 7 - squashkiwi/backup.sh | 17 - squashkiwi/config/.template_info.env | 21 -- squashkiwi/config/service.env | 9 - squashkiwi/destroy.sh | 14 - squashkiwi/install.sh | 22 -- squashkiwi/logs.sh | 7 - squashkiwi/ports.sh | 5 - squashkiwi/restore.sh | 22 -- squashkiwi/ssh.sh | 13 - squashkiwi/start.sh | 24 -- squashkiwi/status.sh | 13 - squashkiwi/stop.sh | 7 - squashkiwi/uninstall.sh | 15 - 42 files changed, 2171 deletions(-) delete mode 100644 squashkiwi-streaming/.gitignore delete mode 100755 squashkiwi-streaming/_paths.sh delete mode 100755 squashkiwi-streaming/backup.sh delete mode 100644 squashkiwi-streaming/config/.template_info.env delete mode 100644 squashkiwi-streaming/config/docker-compose.yml delete mode 100644 squashkiwi-streaming/config/mediamtx.yml delete mode 100644 squashkiwi-streaming/config/nginx.conf delete mode 100644 squashkiwi-streaming/config/overlay/Dockerfile delete mode 100644 squashkiwi-streaming/config/overlay/overlay_service.py delete mode 100644 squashkiwi-streaming/config/overlay/requirements.txt delete mode 100644 squashkiwi-streaming/config/service.env delete mode 100644 squashkiwi-streaming/config/transcoder/Dockerfile delete mode 100644 squashkiwi-streaming/config/transcoder/transcoder.sh delete mode 100644 squashkiwi-streaming/config/web/index.html delete mode 100644 squashkiwi-streaming/config/web/test.html delete mode 100644 squashkiwi-streaming/config/web/webrtc.html delete mode 100755 squashkiwi-streaming/destroy.sh delete mode 100755 squashkiwi-streaming/install.sh delete mode 100755 squashkiwi-streaming/logs.sh delete mode 100755 squashkiwi-streaming/ports.sh delete mode 100755 squashkiwi-streaming/restore.sh delete mode 100755 squashkiwi-streaming/ssh.sh delete mode 100755 squashkiwi-streaming/start.sh delete mode 100755 squashkiwi-streaming/status.sh delete mode 100755 squashkiwi-streaming/stop.sh delete mode 100755 squashkiwi-streaming/test-camera.sh delete mode 100755 squashkiwi-streaming/test-substream.sh delete mode 100755 squashkiwi-streaming/uninstall.sh delete mode 100755 squashkiwi/_paths.sh delete mode 100755 squashkiwi/backup.sh delete mode 100644 squashkiwi/config/.template_info.env delete mode 100644 squashkiwi/config/service.env delete mode 100755 squashkiwi/destroy.sh delete mode 100755 squashkiwi/install.sh delete mode 100755 squashkiwi/logs.sh delete mode 100755 squashkiwi/ports.sh delete mode 100755 squashkiwi/restore.sh delete mode 100755 squashkiwi/ssh.sh delete mode 100755 squashkiwi/start.sh delete mode 100755 squashkiwi/status.sh delete mode 100755 squashkiwi/stop.sh delete mode 100755 squashkiwi/uninstall.sh diff --git a/squashkiwi-streaming/.gitignore b/squashkiwi-streaming/.gitignore deleted file mode 100644 index 58786aa..0000000 --- a/squashkiwi-streaming/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ - -# Playwright -node_modules/ -/test-results/ -/playwright-report/ -/blob-report/ -/playwright/.cache/ diff --git a/squashkiwi-streaming/_paths.sh b/squashkiwi-streaming/_paths.sh deleted file mode 100755 index ac173ae..0000000 --- a/squashkiwi-streaming/_paths.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# Path configuration for squashkiwi-streaming - -# get_squashkiwi_streaming_paths() { -# echo "${LOCAL_DATA_FOLDER}/config" -# echo "${LOCAL_DATA_FOLDER}/recordings" -# echo "${LOCAL_DATA_FOLDER}/config/overlay" -# echo "${LOCAL_DATA_FOLDER}/config/web" -# } - - -get_squashkiwi_streaming_paths() { - echo "path:localpath:${LOCAL_DATA_FOLDER}" -} \ No newline at end of file diff --git a/squashkiwi-streaming/backup.sh b/squashkiwi-streaming/backup.sh deleted file mode 100755 index f5dd984..0000000 --- a/squashkiwi-streaming/backup.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" "BACKUP_FILE" "TEMP_DIR" - -# shellcheck disable=SC2046 -backup_items $(get_squashkiwi_streaming_paths) || _die "Failed to create backup" - -echo "Backup created successfully (recordings excluded)" diff --git a/squashkiwi-streaming/config/.template_info.env b/squashkiwi-streaming/config/.template_info.env deleted file mode 100644 index 68645a6..0000000 --- a/squashkiwi-streaming/config/.template_info.env +++ /dev/null @@ -1,16 +0,0 @@ -# DO NOT EDIT THIS FILE FOR YOUR SERVICE! -# This file is replaced from the template whenever there is an update. -# Edit the service.env file to make changes. - -# Template to use - always required! -TEMPLATE=squashkiwi-streaming -REQUIRES_HOST_ROOT=false -REQUIRES_DOCKER=true -REQUIRES_DOCKER_ROOT=false - -# Application settings -MEDIAMTX_PORT=8554 -HLS_PORT=8888 -WEBRTC_PORT=8889 -WEB_PORT=80 - diff --git a/squashkiwi-streaming/config/docker-compose.yml b/squashkiwi-streaming/config/docker-compose.yml deleted file mode 100644 index 5748fff..0000000 --- a/squashkiwi-streaming/config/docker-compose.yml +++ /dev/null @@ -1,150 +0,0 @@ -services: - # MediaMTX - RTSP/HLS/WebRTC streaming server - mediamtx: - image: bluenviron/mediamtx:latest - container_name: ${PROJECT_NAME}-mediamtx - restart: unless-stopped - network_mode: host - volumes: - - ./mediamtx.yml:/mediamtx.yml - - ${RECORDINGS_FOLDER}:/recordings - environment: - MTX_PROTOCOLS: tcp - # Main stream configuration - MTX_PATHS_COURT_MAIN_SOURCE: ${MTX_PATHS_COURT_MAIN_SOURCE} - MTX_PATHS_COURT_MAIN_SOURCEPROTOCOL: tcp - MTX_PATHS_COURT_MAIN_RECORD: "yes" - MTX_PATHS_COURT_MAIN_RECORDPATH: "/recordings/%path/%Y-%m-%d_%H-%M-%S-%f.mp4" - MTX_PATHS_COURT_MAIN_RECORDFORMAT: fmp4 - MTX_PATHS_COURT_MAIN_RECORDSEGMENTDURATION: 1h - MTX_PATHS_COURT_MAIN_RECORDDELETEAFTER: 24h - # Sub stream configuration (usually H264) - MTX_PATHS_COURT_SUB_SOURCE: ${MTX_PATHS_COURT_SUB_SOURCE} - MTX_PATHS_COURT_SUB_SOURCEPROTOCOL: tcp - # Legacy court path - original H265 stream - MTX_PATHS_COURT_SOURCE: ${MTX_PATHS_COURT_SOURCE} - MTX_PATHS_COURT_SOURCEPROTOCOL: tcp - # Force all paths to start immediately - MTX_PATHDEFAULTS_SOURCEONDEMAND: "no" - # Authentication disabled for testing - # MTX_PATHDEFAULTS_PUBLISHUSER: ${MEDIAMTX_USER} - # MTX_PATHDEFAULTS_PUBLISHPASS: ${MEDIAMTX_PASS} - # MTX_PATHDEFAULTS_READUSER: ${MEDIAMTX_USER} - # MTX_PATHDEFAULTS_READPASS: ${MEDIAMTX_PASS} - healthcheck: - test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:9997/v2/paths/list"] - interval: 30s - timeout: 10s - retries: 3 - - # FFmpeg transcoder for H265 to H264 with score overlay - transcoder: - build: ./transcoder - image: ${PROJECT_NAME}-transcoder:latest - container_name: ${PROJECT_NAME}-transcoder - restart: unless-stopped - network_mode: host - volumes: - - score-data:/tmp:rw - depends_on: - - mediamtx - - # Score overlay and recording service - overlay-service: - build: ./overlay - image: ${PROJECT_NAME}-overlay:latest - container_name: ${PROJECT_NAME}-overlay - restart: unless-stopped - network_mode: host - depends_on: - - mediamtx - volumes: - - ${RECORDINGS_FOLDER}:/recordings - - score-data:/tmp:rw - environment: - - SQUASHKIWI_API=${SQUASHKIWI_API} - - CLUB_CODE=${CLUB_CODE} - - COURT_NUMBER=${COURT_NUMBER} - - COURT_NAME=${COURT_NAME} - - MEDIAMTX_API=http://localhost:9997 - - RECORDING_PATH=/recordings - - IDLE_TIMEOUT=${IDLE_TIMEOUT} - - RECORDING_RETENTION_DAYS=${RECORDING_RETENTION_DAYS} - healthcheck: - test: ["CMD", "pgrep", "-f", "overlay_service.py"] - interval: 30s - timeout: 10s - retries: 3 - - # Nginx web server - nginx: - image: nginx:alpine - container_name: ${PROJECT_NAME}-nginx - restart: unless-stopped - network_mode: host - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf:ro - - ./web:/usr/share/nginx/html:ro - - ${RECORDINGS_FOLDER}:/recordings:ro - - nginx-cache:/var/cache/nginx - depends_on: - - mediamtx - healthcheck: - test: ["CMD", "wget", "-q", "-O", "-", "http://localhost/health"] - interval: 30s - timeout: 10s - retries: 3 - - # Optional: Cloudflare tunnel - cloudflared: - image: cloudflare/cloudflared:latest - container_name: ${PROJECT_NAME}-tunnel - restart: unless-stopped - command: tunnel run - environment: - - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN} - profiles: - - tunnel - - # Optional: Prometheus monitoring - prometheus: - image: prom/prometheus:latest - container_name: ${PROJECT_NAME}-prometheus - restart: unless-stopped - ports: - - "9090:9090" - volumes: - - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro - - prometheus-data:/prometheus - command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' - profiles: - - monitoring - - # Optional: Grafana - grafana: - image: grafana/grafana:latest - container_name: ${PROJECT_NAME}-grafana - restart: unless-stopped - ports: - - "3000:3000" - volumes: - - grafana-data:/var/lib/grafana - environment: - - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD} - depends_on: - - prometheus - profiles: - - monitoring - -volumes: - nginx-cache: - prometheus-data: - grafana-data: - score-data: - -networks: - default: - name: ${PROJECT_NAME} - driver: bridge \ No newline at end of file diff --git a/squashkiwi-streaming/config/mediamtx.yml b/squashkiwi-streaming/config/mediamtx.yml deleted file mode 100644 index 645619c..0000000 --- a/squashkiwi-streaming/config/mediamtx.yml +++ /dev/null @@ -1,47 +0,0 @@ -# MediaMTX Configuration for SquashKiwi Streaming - -# General Settings -logLevel: info -logDestinations: [stdout] - -# API Configuration -api: yes -apiAddress: :9997 -apiAllowOrigin: '*' - -# Metrics -metrics: yes -metricsAddress: :9998 - -# RTSP Server -rtsp: yes -rtspAddress: :8554 -rtspTransports: [tcp, udp] - -# HLS Server -hls: yes -hlsAddress: :8888 -hlsAllowOrigin: '*' -hlsSegmentCount: 3 -hlsSegmentDuration: 1s -hlsPartDuration: 200ms -hlsAlwaysRemux: yes - -# WebRTC Server -webrtc: yes -webrtcAddress: :8889 -webrtcAllowOrigin: '*' - -# Path defaults -pathDefaults: - # Authentication disabled for testing - # readUser: stream - # readPass: squashkiwi - # publishUser: stream - # publishPass: squashkiwi - -# Path Configuration -paths: - # Transcoded H264 stream - court_h264: - # This path will receive the transcoded stream from ffmpeg \ No newline at end of file diff --git a/squashkiwi-streaming/config/nginx.conf b/squashkiwi-streaming/config/nginx.conf deleted file mode 100644 index 5b5d336..0000000 --- a/squashkiwi-streaming/config/nginx.conf +++ /dev/null @@ -1,120 +0,0 @@ -events { - worker_connections 1024; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - gzip on; - - # Cache settings for HLS - proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=hls_cache:10m max_size=1g inactive=60m use_temp_path=off; - - server { - listen 8880; - server_name _; - - root /usr/share/nginx/html; - index index.html; - - # Health check - location /health { - access_log off; - return 200 "OK\n"; - add_header Content-Type text/plain; - } - - # Main web interface - location / { - try_files $uri $uri/ /index.html; - add_header Cache-Control "no-cache, no-store, must-revalidate"; - } - - # HLS streams proxy - location /hls/ { - proxy_pass http://[::1]:8888/; - proxy_http_version 1.1; - - # Forward authentication headers - proxy_set_header Authorization $http_authorization; - - # CORS headers - add_header Access-Control-Allow-Origin *; - add_header Access-Control-Allow-Methods "GET, OPTIONS"; - add_header Access-Control-Allow-Headers "Range, Authorization"; - - # Cache HLS segments - proxy_cache hls_cache; - proxy_cache_valid 200 1m; - proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; - - proxy_buffering off; - proxy_request_buffering off; - } - - # WebRTC signaling (WHEP) - location /webrtc/ { - proxy_pass http://[::1]:8889/; - proxy_http_version 1.1; - - # CORS headers for WebRTC - add_header Access-Control-Allow-Origin * always; - add_header Access-Control-Allow-Methods "GET, POST, OPTIONS, PATCH, DELETE" always; - add_header Access-Control-Allow-Headers "Authorization, Content-Type, If-Match" always; - add_header Access-Control-Expose-Headers "Link" always; - - # Handle OPTIONS preflight - if ($request_method = OPTIONS) { - return 204; - } - - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header Authorization $http_authorization; - - proxy_buffering off; - proxy_request_buffering off; - proxy_read_timeout 86400; - proxy_send_timeout 86400; - } - - # MediaMTX API - location /api/mediamtx/ { - proxy_pass http://[::1]:9997/; - allow 127.0.0.1; - allow 172.16.0.0/12; - deny all; - } - - # Recordings - location /recordings/ { - alias /recordings/; - autoindex on; - autoindex_exact_size off; - autoindex_localtime on; - add_header Accept-Ranges bytes; - add_header Content-Disposition "inline"; - } - - # API endpoint for recordings list - location /api/recordings { - default_type application/json; - return 200 '{"recordings": []}'; - } - - # Metrics - location /metrics { - proxy_pass http://localhost:9998/metrics; - allow 127.0.0.1; - allow 172.16.0.0/12; - deny all; - } - } -} \ No newline at end of file diff --git a/squashkiwi-streaming/config/overlay/Dockerfile b/squashkiwi-streaming/config/overlay/Dockerfile deleted file mode 100644 index 4c3e0a9..0000000 --- a/squashkiwi-streaming/config/overlay/Dockerfile +++ /dev/null @@ -1,33 +0,0 @@ -FROM python:3.11-slim - -# Install FFmpeg and fonts -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ffmpeg \ - fonts-dejavu-core \ - curl \ - && rm -rf /var/lib/apt/lists/* - -WORKDIR /app - -# Copy requirements and install -COPY requirements.txt . -RUN pip install --no-cache-dir -r requirements.txt - -# Copy application -COPY overlay_service.py . - -# Create recordings directory -RUN mkdir -p /recordings - -# Create user but don't switch to it - need root for shared volume -RUN useradd -m -s /bin/bash overlay && \ - chown -R overlay:overlay /app /recordings -# Running as root to access shared /tmp volume -# USER overlay - -# Health check -HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ - CMD python -c "import sys; sys.exit(0)" - -CMD ["python", "-u", "overlay_service.py"] \ No newline at end of file diff --git a/squashkiwi-streaming/config/overlay/overlay_service.py b/squashkiwi-streaming/config/overlay/overlay_service.py deleted file mode 100644 index 919dff0..0000000 --- a/squashkiwi-streaming/config/overlay/overlay_service.py +++ /dev/null @@ -1,327 +0,0 @@ -#!/usr/bin/env python3 -""" -SquashKiwi Score Overlay Service -Fetches scores from SquashKiwi API and manages recordings -""" - -import asyncio -import aiohttp -import json -import subprocess -import os -import time -import signal -import sys -from datetime import datetime, timedelta -from typing import Optional, Dict, Any -import logging - -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' -) -logger = logging.getLogger(__name__) - -class ScoreOverlayService: - def __init__(self): - # Load configuration from environment - self.api_url = os.getenv('SQUASHKIWI_API', 'https://squash.kiwi/api') - self.club_code = os.getenv('CLUB_CODE', 'OTOG') - self.court_number = os.getenv('COURT_NUMBER', '1') - self.court_id = f"{self.club_code.lower()}{self.court_number}" - self.mediamtx_api = os.getenv('MEDIAMTX_API', 'http://localhost:9997') - self.recording_path = os.getenv('RECORDING_PATH', '/recordings') - - # State management - self.current_score = {"player1": 0, "player2": 0, "games": "0-0", "serving": None} - self.recording_process = None - self.recording_filename = None - self.last_score_change = time.time() - self.match_start_time = None - self.idle_timeout = int(os.getenv('IDLE_TIMEOUT', '300')) - - # Ensure recording directory exists - os.makedirs(self.recording_path, exist_ok=True) - - # Setup signal handlers - signal.signal(signal.SIGINT, self.signal_handler) - signal.signal(signal.SIGTERM, self.signal_handler) - - logger.info(f"Score overlay service initialized for court {self.court_id}") - - def signal_handler(self, signum, frame): - """Handle shutdown signals gracefully""" - logger.info(f"Received signal {signum}, shutting down...") - if self.recording_process: - self.stop_recording_sync() - sys.exit(0) - - async def fetch_score(self) -> Optional[Dict[str, Any]]: - """Fetch current score from SquashKiwi API""" - try: - timeout = aiohttp.ClientTimeout(total=5) - async with aiohttp.ClientSession(timeout=timeout) as session: - # Use format: https://squash.kiwi/api/otog2/score - url = f"{self.api_url}/{self.court_id}/score" - async with session.get(url) as resp: - if resp.status == 200: - data = await resp.json() - # Check if match is active - if data.get('match_active', False): - return data - else: - logger.debug(f"No active match on court {self.court_id}") - return None - else: - logger.warning(f"API returned status {resp.status}") - return None - except Exception as e: - logger.error(f"Error fetching score: {e}") - return None - - async def check_stream_health(self) -> bool: - """Check if the stream is healthy""" - try: - timeout = aiohttp.ClientTimeout(total=2) - async with aiohttp.ClientSession(timeout=timeout) as session: - url = f"{self.mediamtx_api}/v3/paths/list" - async with session.get(url) as resp: - if resp.status == 200: - data = await resp.json() - paths = data.get('items', []) - # Check if either court or court_h264 path exists (we're transcoding) - return any(p.get('name') in ['court', 'court_h264'] for p in paths) - return False - except Exception as e: - logger.error(f"Failed to check stream health: {e}") - return False - - def format_score_text(self) -> str: - """Format the score for overlay display""" - games = self.current_score.get('games', '0-0') - p1_score = self.current_score.get('player1', 0) - p2_score = self.current_score.get('player2', 0) - p1_name = self.current_score.get('player1_name', 'Player 1')[:15] - p2_name = self.current_score.get('player2_name', 'Player 2')[:15] - - serving = self.current_score.get('serving') - serve1 = ' •' if serving == 1 else '' - serve2 = ' •' if serving == 2 else '' - - return f"{games} | {p1_name}: {p1_score}{serve1} - {p2_name}: {p2_score}{serve2}" - - async def start_recording(self): - """Start recording the match""" - if self.recording_process and self.recording_process.poll() is None: - logger.debug("Recording already in progress") - return - - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - court_folder = os.path.join(self.recording_path, self.court_id) - os.makedirs(court_folder, exist_ok=True) - - self.recording_filename = os.path.join(court_folder, f"match_{timestamp}.mp4") - self.match_start_time = datetime.now() - - logger.info(f"Starting recording: {self.recording_filename}") - - score_text = self.format_score_text() - - cmd = [ - 'ffmpeg', - '-y', - '-i', 'rtsp://localhost:8554/court', - '-vf', f"drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:" - f"text='{score_text}':fontcolor=white:fontsize=30:" - f"box=1:boxcolor=black@0.5:boxborderw=5:x=10:y=10:" - f"reload=1:textfile=/tmp/score.txt", - '-c:v', 'libx264', - '-preset', 'fast', - '-crf', '23', - '-c:a', 'aac', - '-b:a', '128k', - '-movflags', '+faststart', - self.recording_filename - ] - - with open('/tmp/score.txt', 'w') as f: - f.write(score_text) - - try: - self.recording_process = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ) - logger.info(f"Recording process started with PID {self.recording_process.pid}") - except Exception as e: - logger.error(f"Failed to start recording: {e}") - self.recording_process = None - - async def stop_recording(self): - """Stop recording the match""" - if not self.recording_process or self.recording_process.poll() is not None: - logger.debug("No active recording to stop") - return - - logger.info("Stopping recording due to inactivity") - - try: - self.recording_process.send_signal(signal.SIGINT) - - try: - await asyncio.wait_for( - asyncio.create_subprocess_exec('wait', str(self.recording_process.pid)), - timeout=5.0 - ) - except asyncio.TimeoutError: - self.recording_process.kill() - logger.warning("Had to force kill recording process") - - if self.match_start_time: - duration = datetime.now() - self.match_start_time - logger.info(f"Recording duration: {duration}") - - metadata_file = self.recording_filename.replace('.mp4', '.json') - metadata = { - 'court_id': self.court_id, - 'start_time': self.match_start_time.isoformat(), - 'end_time': datetime.now().isoformat(), - 'duration': str(duration), - 'final_score': self.current_score - } - - try: - with open(metadata_file, 'w') as f: - json.dump(metadata, f, indent=2) - logger.info(f"Metadata saved to {metadata_file}") - except Exception as e: - logger.error(f"Failed to save metadata: {e}") - - except Exception as e: - logger.error(f"Error stopping recording: {e}") - finally: - self.recording_process = None - self.recording_filename = None - self.match_start_time = None - - def stop_recording_sync(self): - """Synchronous version of stop_recording for signal handler""" - if self.recording_process and self.recording_process.poll() is None: - logger.info("Stopping recording (sync)") - self.recording_process.terminate() - self.recording_process.wait(timeout=5) - - async def update_overlay_text(self): - """Update the overlay text file""" - score_text = self.format_score_text() - try: - with open('/tmp/score.txt', 'w') as f: - f.write(score_text) - except Exception as e: - logger.error(f"Failed to update overlay text: {e}") - - async def cleanup_old_recordings(self): - """Remove recordings older than retention period""" - retention_days = int(os.getenv('RECORDING_RETENTION_DAYS', '30')) - cutoff_date = datetime.now() - timedelta(days=retention_days) - - try: - for root, dirs, files in os.walk(self.recording_path): - for file in files: - if file.endswith('.mp4'): - file_path = os.path.join(root, file) - file_time = datetime.fromtimestamp(os.path.getmtime(file_path)) - if file_time < cutoff_date: - os.remove(file_path) - logger.info(f"Deleted old recording: {file}") - metadata_file = file_path.replace('.mp4', '.json') - if os.path.exists(metadata_file): - os.remove(metadata_file) - except Exception as e: - logger.error(f"Error during cleanup: {e}") - - async def main_loop(self): - """Main service loop""" - logger.info("Starting main service loop") - - # Initialize overlay text - court_name = os.getenv('COURT_NAME', f'Court {self.court_number}') - try: - # Create file with write permissions for all - with open('/tmp/score.txt', 'w') as f: - f.write(f"{court_name} - Waiting for match...") - os.chmod('/tmp/score.txt', 0o666) - except PermissionError: - # If file exists and we can't write, try to remove and recreate - try: - os.remove('/tmp/score.txt') - with open('/tmp/score.txt', 'w') as f: - f.write(f"{court_name} - Waiting for match...") - os.chmod('/tmp/score.txt', 0o666) - except: - logger.error("Cannot create score.txt file - check permissions") - - await self.cleanup_old_recordings() - last_cleanup = datetime.now() - - while True: - try: - stream_healthy = await self.check_stream_health() - if not stream_healthy: - logger.warning("Stream not healthy, waiting...") - await asyncio.sleep(10) - continue - - score = await self.fetch_score() - - if score: - if score != self.current_score: - self.current_score = score - self.last_score_change = time.time() - - logger.info(f"Score updated: {self.format_score_text()}") - await self.update_overlay_text() - - if not self.recording_process or self.recording_process.poll() is not None: - await self.start_recording() - - idle_time = time.time() - self.last_score_change - if self.recording_process and idle_time > self.idle_timeout: - logger.info(f"Match idle for {idle_time:.0f} seconds") - await self.stop_recording() - - else: - if self.recording_process: - logger.info("No active match detected") - await self.stop_recording() - - # Update overlay to show no active match - court_name = os.getenv('COURT_NAME', f'Court {self.court_number}') - with open('/tmp/score.txt', 'w') as f: - f.write(f"{court_name} - No active match") - - if datetime.now() - last_cleanup > timedelta(days=1): - await self.cleanup_old_recordings() - last_cleanup = datetime.now() - - await asyncio.sleep(1) - - except Exception as e: - logger.error(f"Error in main loop: {e}") - await asyncio.sleep(5) - - async def run(self): - """Run the service""" - logger.info("SquashKiwi Score Overlay Service starting...") - await self.main_loop() - -if __name__ == "__main__": - service = ScoreOverlayService() - try: - asyncio.run(service.run()) - except KeyboardInterrupt: - logger.info("Service stopped by user") - except Exception as e: - logger.error(f"Service crashed: {e}") - sys.exit(1) \ No newline at end of file diff --git a/squashkiwi-streaming/config/overlay/requirements.txt b/squashkiwi-streaming/config/overlay/requirements.txt deleted file mode 100644 index 5486541..0000000 --- a/squashkiwi-streaming/config/overlay/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -aiohttp==3.9.1 -python-dateutil==2.8.2 -tenacity==8.2.3 \ No newline at end of file diff --git a/squashkiwi-streaming/config/service.env b/squashkiwi-streaming/config/service.env deleted file mode 100644 index c7dd26f..0000000 --- a/squashkiwi-streaming/config/service.env +++ /dev/null @@ -1,49 +0,0 @@ -# SquashKiwi Streaming Configuration -# Edit this file to configure your streaming service - -# Data folders -LOCAL_DATA_FOLDER="/home/dropshell/squashkiwi-streaming-data" -RECORDINGS_FOLDER="/home/dropshell/squashkiwi-streaming-recordings" - -# Project Name used in docker-compose.yml, must be unique on the server. -PROJECT_NAME="sk-streaming" - -# Camera Configuration -# Note: If password contains special characters (! @ # $ & %), they will be automatically URL-encoded -# Or you can manually encode them: ! = %21, @ = %40, # = %23, $ = %24, & = %26 -CAMERA_IP=192.168.1.100 -CAMERA_USER=admin -CAMERA_PASSWORD=changeme -CAMERA_RTSP_PORT=554 - -# Court Configuration -# CLUB_CODE: Your club's code (e.g., OTOG for Otago, WELL for Wellington) -# COURT_NUMBER: The court number (1, 2, 3, etc.) -CLUB_CODE=OTOG -COURT_NUMBER=1 -COURT_NAME="Court 1" - -# SquashKiwi API -SQUASHKIWI_API=https://squash.kiwi/api - -# Recording Settings -RECORDING_RETENTION_DAYS=30 -RECORDING_QUALITY=high -IDLE_TIMEOUT=300 - -# Network Settings -HOST_PORT=8880 -PUBLIC_IP= - -# MediaMTX Authentication (optional - remove values to disable auth) -MEDIAMTX_USER= -MEDIAMTX_PASS= - -# SSH User automatically set on service creation. -SSH_USER="root" - -# Optional: Cloudflare Tunnel -CLOUDFLARE_TUNNEL_TOKEN= - -# Optional: Monitoring -GRAFANA_PASSWORD=admin diff --git a/squashkiwi-streaming/config/transcoder/Dockerfile b/squashkiwi-streaming/config/transcoder/Dockerfile deleted file mode 100644 index c877ee8..0000000 --- a/squashkiwi-streaming/config/transcoder/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -FROM linuxserver/ffmpeg:latest - -# Install fonts for text overlay -RUN apt-get update && \ - apt-get install -y --no-install-recommends fonts-dejavu-core && \ - rm -rf /var/lib/apt/lists/* - -# Copy transcoder script -COPY transcoder.sh /transcoder.sh -RUN chmod +x /transcoder.sh - -# Create score file directory -RUN mkdir -p /tmp - -ENTRYPOINT ["/transcoder.sh"] \ No newline at end of file diff --git a/squashkiwi-streaming/config/transcoder/transcoder.sh b/squashkiwi-streaming/config/transcoder/transcoder.sh deleted file mode 100644 index 5da5433..0000000 --- a/squashkiwi-streaming/config/transcoder/transcoder.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# Transcoder with live score overlay for SquashKiwi streaming - -# Create initial score file if it doesn't exist -SCORE_FILE="/tmp/score.txt" -if [ ! -f "$SCORE_FILE" ]; then - echo "Waiting for match..." > "$SCORE_FILE" -fi - -# Start ffmpeg with drawtext filter for score overlay -exec ffmpeg \ - -rtsp_transport tcp \ - -i rtsp://localhost:8554/court \ - -vf "drawtext=fontfile=/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf:\ -textfile='$SCORE_FILE':\ -reload=1:\ -fontcolor=white:\ -fontsize=24:\ -box=1:\ -boxcolor=black@0.7:\ -boxborderw=5:\ -x=10:\ -y=10" \ - -c:v libx264 \ - -preset ultrafast \ - -tune zerolatency \ - -g 30 \ - -keyint_min 30 \ - -b:v 2M \ - -maxrate 2M \ - -bufsize 1M \ - -f rtsp \ - -rtsp_transport tcp \ - rtsp://localhost:8554/court_h264 \ No newline at end of file diff --git a/squashkiwi-streaming/config/web/index.html b/squashkiwi-streaming/config/web/index.html deleted file mode 100644 index ec337a7..0000000 --- a/squashkiwi-streaming/config/web/index.html +++ /dev/null @@ -1,329 +0,0 @@ - - - - - - SquashKiwi Court Stream - - - - -
-
-

🎾 SquashKiwi Court Stream

-
- -
-
- -
-
-
- Connecting... -
-
- - - -
-
- - -
-
-
- -
-

Recent Recordings

-
-
-
Loading recordings...
-
-
-
-
- - - - \ No newline at end of file diff --git a/squashkiwi-streaming/config/web/test.html b/squashkiwi-streaming/config/web/test.html deleted file mode 100644 index 5bb740a..0000000 --- a/squashkiwi-streaming/config/web/test.html +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - Stream Test - - - -

SquashKiwi Stream Test Page

- -
-

Available Paths

- -
Click to check available paths...
-
- -
-

Test Streams

- - - - -
Select a stream to test...
-
- -
-

HLS Test

- -
HLS player ready...
-
- - - - - \ No newline at end of file diff --git a/squashkiwi-streaming/config/web/webrtc.html b/squashkiwi-streaming/config/web/webrtc.html deleted file mode 100644 index a67096d..0000000 --- a/squashkiwi-streaming/config/web/webrtc.html +++ /dev/null @@ -1,299 +0,0 @@ - - - - - - SquashKiwi Court Stream - WebRTC - - - -
-
-

🎾 SquashKiwi Court Stream (WebRTC)

-
- -
-
- -
▶️ Click to Play
-
-
-
- Connecting... -
-
- - -
-
-
- - - -
-

WebRTC Stream

-

This player uses WebRTC for lower latency streaming. It should work with H265/HEVC streams.

-
-
- - - - \ No newline at end of file diff --git a/squashkiwi-streaming/destroy.sh b/squashkiwi-streaming/destroy.sh deleted file mode 100755 index 1e11d4f..0000000 --- a/squashkiwi-streaming/destroy.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "LOCAL_DATA_FOLDER" "PROJECT_NAME" "RECORDINGS_FOLDER" - -"${SCRIPT_DIR}/uninstall.sh" - -# shellcheck disable=SC2046 -destroy_items $(get_squashkiwi_streaming_paths) || _die "Failed to destroy ${LOCAL_DATA_FOLDER}" -rm -rf "${RECORDINGS_FOLDER}" - -echo "Destroyed ${PROJECT_NAME}" - diff --git a/squashkiwi-streaming/install.sh b/squashkiwi-streaming/install.sh deleted file mode 100755 index 93ae1f4..0000000 --- a/squashkiwi-streaming/install.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" "CAMERA_IP" "CLUB_CODE" "COURT_NUMBER" "RECORDINGS_FOLDER" - -# Create directories -# shellcheck disable=SC2046 -create_items $(get_squashkiwi_streaming_paths) || _die "Failed to create directories" -mkdir -p "${RECORDINGS_FOLDER}/court_main" -mkdir -p "${RECORDINGS_FOLDER}/court_sub" -mkdir -p "${LOCAL_DATA_FOLDER}/config" -mkdir -p "${LOCAL_DATA_FOLDER}/config/overlay" -mkdir -p "${LOCAL_DATA_FOLDER}/config/web" - -# Copy configuration files -cp -r "${SCRIPT_DIR}/config/"* "${LOCAL_DATA_FOLDER}/config/" || _die "Failed to copy config files" - -# URL-encode the camera password if it contains special characters -# Only encode if not already encoded (check for % sign) -if [[ "${CAMERA_PASSWORD}" == *[!\@\#\$\&]* ]] && [[ "${CAMERA_PASSWORD}" != *%* ]]; then - echo "Note: Camera password contains special characters. Encoding for RTSP URL..." - CAMERA_PASSWORD=$(echo -n "${CAMERA_PASSWORD}" | sed 's/!/%21/g; s/@/%40/g; s/#/%23/g; s/\$/%24/g; s/&/%26/g') -fi - -# Create .env file for docker-compose with all required variables -echo "Creating environment file for docker-compose..." -cat > "${LOCAL_DATA_FOLDER}/config/.env" < /dev/null 2>&1; then - echo "✓ Camera IP is reachable" -else - echo "⚠ Warning: Camera IP ${CAMERA_IP} is not reachable. Please check camera connection." -fi - -# Build overlay service -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" -docker compose build overlay-service || _die "Failed to build overlay service" - -# Stop any existing containers -bash "${SCRIPT_DIR}/stop.sh" 2>/dev/null || true - -# Start services -bash "${SCRIPT_DIR}/start.sh" || _die "Failed to start services" - -echo "" -echo "Installation of ${PROJECT_NAME} complete!" -echo "Access the stream at: http://$(hostname -I | awk '{print $1}'):${HOST_PORT}" -echo "" -echo "To enable optional features:" -echo " - Cloudflare tunnel: Set CLOUDFLARE_TUNNEL_TOKEN in service.env and run: docker compose --profile tunnel up -d" -echo " - Monitoring: docker compose --profile monitoring up -d" \ No newline at end of file diff --git a/squashkiwi-streaming/logs.sh b/squashkiwi-streaming/logs.sh deleted file mode 100755 index 5648f3b..0000000 --- a/squashkiwi-streaming/logs.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "LOCAL_DATA_FOLDER" - -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" - -# Follow logs for all services -docker compose logs -f \ No newline at end of file diff --git a/squashkiwi-streaming/ports.sh b/squashkiwi-streaming/ports.sh deleted file mode 100755 index 2d2b813..0000000 --- a/squashkiwi-streaming/ports.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" - -echo "${HOST_PORT:-8880}" -echo "8554" -echo "8888" -echo "8889" -echo "9997" -echo "9998" -echo "9090" -echo "3000" - -# Port Requirements: - -# - 8880 - Web interface (changed from 8080) -# - 8554 - RTSP server -# - 8888 - HLS streaming -# - 8889 - WebRTC signaling -# - 9997 - MediaMTX API -# - 9998 - Metrics -# - 9090 - Prometheus (optional) -# - 3000 - Grafana (optional) diff --git a/squashkiwi-streaming/restore.sh b/squashkiwi-streaming/restore.sh deleted file mode 100755 index e705ab3..0000000 --- a/squashkiwi-streaming/restore.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" "BACKUP_FILE" "TEMP_DIR" - -# RESTORE SCRIPT -# The restore script is OPTIONAL. -# It is used to restore the service on the server from a backup file. -# It is called with one argument: the path to the backup file. - -# # Stop container before backup -"${SCRIPT_DIR}/uninstall.sh" || _die "Failed to uninstall service before restore" - -# shellcheck disable=SC2046 -restore_items $(get_squashkiwi_streaming_paths) || _die "Failed to restore data folder from backup" - -# reinstall service -"${SCRIPT_DIR}/install.sh" || _die "Failed to reinstall service after restore" - -echo "Restore complete! Service is running again on port $HOST_PORT with restored website." diff --git a/squashkiwi-streaming/ssh.sh b/squashkiwi-streaming/ssh.sh deleted file mode 100755 index 3bdc143..0000000 --- a/squashkiwi-streaming/ssh.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "PROJECT_NAME" - -# List running containers -echo "Available containers:" -docker ps --filter "name=${PROJECT_NAME}" --format "table {{.Names}}\t{{.Status}}" - -echo "" -read -p "Enter container name to SSH into (or press Enter for mediamtx): " container - -if [[ -z "$container" ]]; then - container="${PROJECT_NAME}-mediamtx" -fi - -echo "Connecting to ${container}..." -docker exec -it "${container}" /bin/sh \ No newline at end of file diff --git a/squashkiwi-streaming/start.sh b/squashkiwi-streaming/start.sh deleted file mode 100755 index 182e3ca..0000000 --- a/squashkiwi-streaming/start.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" - -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" - -# Check that .env file exists and show configuration -if [[ ! -f "${LOCAL_DATA_FOLDER}/config/.env" ]]; then - _die ".env file not found at ${LOCAL_DATA_FOLDER}/config/.env - run install first" -fi - -echo "Checking .env configuration..." -CONFIGURED_IP=$(grep "MTX_PATHS_COURT_MAIN_SOURCE" "${LOCAL_DATA_FOLDER}/config/.env" | sed -n 's/.*@\([0-9.]*\):.*/\1/p') -echo "Camera IP from .env: ${CONFIGURED_IP}" -echo "Camera IP from service.env: ${CAMERA_IP}" - -# Start docker compose services (docker-compose will read .env file created by install.sh) -echo "Starting ${PROJECT_NAME} services..." - -docker compose up -d || _die "Failed to start Docker Compose services" - -# Wait for services to be healthy -echo "Waiting for services to be healthy..." -sleep 5 - -# Check service health -if docker compose ps | grep -q "healthy"; then - echo "✓ Services are healthy" -else - echo "⚠ Some services may not be healthy yet. Check with: docker compose ps" -fi - -echo "" -echo "${PROJECT_NAME} started successfully!" -echo "Stream URL: http://$(hostname -I | awk '{print $1}'):${HOST_PORT}" -echo "View logs: docker compose logs -f" \ No newline at end of file diff --git a/squashkiwi-streaming/status.sh b/squashkiwi-streaming/status.sh deleted file mode 100755 index c76e993..0000000 --- a/squashkiwi-streaming/status.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" - -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" - -echo "=== ${PROJECT_NAME} Status ===" -echo "" - -# Show container status -docker compose ps - -echo "" -echo "=== Stream Health ===" - -# Check MediaMTX stream -if curl -s "http://localhost:9997/v2/paths/list" | grep -q "court_main"; then - echo "✓ MediaMTX stream is active" -else - echo "✗ MediaMTX stream is not active" -fi - -# Check web interface -if curl -s "http://localhost:${HOST_PORT:-8080}/health" > /dev/null 2>&1; then - echo "✓ Web interface is accessible" -else - echo "✗ Web interface is not accessible" -fi - -echo "" -echo "=== Recent Logs ===" -docker compose logs --tail=10 \ No newline at end of file diff --git a/squashkiwi-streaming/stop.sh b/squashkiwi-streaming/stop.sh deleted file mode 100755 index 79f35ab..0000000 --- a/squashkiwi-streaming/stop.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" - -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" - -echo "Stopping ${PROJECT_NAME} services..." -docker compose down || _die "Failed to stop Docker Compose services" - -echo "${PROJECT_NAME} stopped" \ No newline at end of file diff --git a/squashkiwi-streaming/test-camera.sh b/squashkiwi-streaming/test-camera.sh deleted file mode 100755 index 49fe3b1..0000000 --- a/squashkiwi-streaming/test-camera.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash -# Test camera RTSP connection -# shellcheck disable=SC1091 - -# Handle both dropshell execution and manual execution -if [ -z "${AGENT_PATH}" ]; then - # Manual execution - set paths relative to template directory - AGENT_PATH="../../../agent/" - # Load from the actual deployed config, not template config - source "../config/.template_info.env" - source "../config/service.env" -fi - -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CAMERA_IP" "CAMERA_USER" "CAMERA_PASSWORD" "CAMERA_RTSP_PORT" - -echo "Testing camera connection..." -echo "Camera IP: ${CAMERA_IP}" -echo "Camera User: ${CAMERA_USER}" -echo "RTSP Port: ${CAMERA_RTSP_PORT}" - -# Test basic network connectivity first -echo "" -echo "Testing network connectivity to camera..." -if ping -c 1 -W 2 "${CAMERA_IP}" > /dev/null 2>&1; then - echo "✓ Camera IP is reachable" -else - echo "✗ Cannot reach camera at ${CAMERA_IP}" - echo " Please check:" - echo " - Camera IP address is correct" - echo " - Camera is powered on" - echo " - Network routing/firewall allows connection" - exit 1 -fi - -# Test RTSP port -echo "" -echo "Testing RTSP port ${CAMERA_RTSP_PORT}..." -if timeout 2 bash -c "echo > /dev/tcp/${CAMERA_IP}/${CAMERA_RTSP_PORT}" 2>/dev/null; then - echo "✓ RTSP port is open" -else - echo "✗ RTSP port ${CAMERA_RTSP_PORT} is not accessible" - echo " Please check:" - echo " - RTSP is enabled on the camera" - echo " - Port number is correct" - echo " - No firewall blocking port ${CAMERA_RTSP_PORT}" - exit 1 -fi - -# URL-encode the password if it contains special characters -ENCODED_PASSWORD=$(echo -n "${CAMERA_PASSWORD}" | sed 's/!/%21/g; s/@/%40/g; s/#/%23/g; s/\$/%24/g; s/&/%26/g') - -RTSP_URL="rtsp://${CAMERA_USER}:${ENCODED_PASSWORD}@${CAMERA_IP}:${CAMERA_RTSP_PORT}/cam/realmonitor?channel=1&subtype=0" - -echo "" -echo "Testing RTSP URL (password hidden): rtsp://${CAMERA_USER}:****@${CAMERA_IP}:${CAMERA_RTSP_PORT}/cam/realmonitor?channel=1&subtype=0" - -# Test with ffprobe -echo "" -echo "Testing with ffprobe (10 second timeout)..." -timeout 10 docker run --rm --network host \ - --entrypoint ffprobe \ - linuxserver/ffmpeg:latest \ - -v error \ - -rtsp_transport tcp \ - -timeout 5000000 \ - "${RTSP_URL}" 2>&1 | head -20 - -if [ $? -eq 0 ]; then - echo "✓ Camera connection successful!" -else - echo "✗ Camera connection failed" - echo "" - echo "Trying alternative RTSP paths..." - - # Try without subtype parameter - ALT_URL="rtsp://${CAMERA_USER}:${ENCODED_PASSWORD}@${CAMERA_IP}:${CAMERA_RTSP_PORT}/cam/realmonitor?channel=1" - docker run --rm --network host --entrypoint ffprobe linuxserver/ffmpeg:latest \ - -v error "${ALT_URL}" 2>&1 | head -5 - - # Try simple path - SIMPLE_URL="rtsp://${CAMERA_USER}:${ENCODED_PASSWORD}@${CAMERA_IP}:${CAMERA_RTSP_PORT}/" - docker run --rm --network host --entrypoint ffprobe linuxserver/ffmpeg:latest \ - -v error "${SIMPLE_URL}" 2>&1 | head -5 -fi - -echo "" -echo "Checking MediaMTX container logs..." -docker logs "${PROJECT_NAME}-mediamtx" --tail 20 2>&1 | grep -E "(ERR|WARN|connected|disconnected|error)" \ No newline at end of file diff --git a/squashkiwi-streaming/test-substream.sh b/squashkiwi-streaming/test-substream.sh deleted file mode 100755 index c5dffd6..0000000 --- a/squashkiwi-streaming/test-substream.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -# Test script to check substream codec - -echo "Testing substream codec..." -echo "RTSP URL: rtsp://admin:Squashkiwiaynsley1!@10.10.1.12:554/cam/realmonitor?channel=1&subtype=1" - -# Use curl to get stream info -timeout 5 curl -I "rtsp://admin:Squashkiwiaynsley1%21@10.10.1.12:554/cam/realmonitor?channel=1&subtype=1" 2>&1 | head -20 - -echo "" -echo "Note: The substream (subtype=1) on Dahua cameras is typically H264" -echo "while the main stream (subtype=0) is H265" \ No newline at end of file diff --git a/squashkiwi-streaming/uninstall.sh b/squashkiwi-streaming/uninstall.sh deleted file mode 100755 index 6209653..0000000 --- a/squashkiwi-streaming/uninstall.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "PROJECT_NAME" "LOCAL_DATA_FOLDER" - -cd "${LOCAL_DATA_FOLDER}/config" || _die "Failed to change to config directory" - -# Stop and remove containers -docker compose down || true - -echo "${PROJECT_NAME} has been uninstalled" diff --git a/squashkiwi/_paths.sh b/squashkiwi/_paths.sh deleted file mode 100755 index 332541e..0000000 --- a/squashkiwi/_paths.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -# Define path items for squashkiwi container -# These are used across backup, restore, create, and destroy operations - -get_squashkiwi_paths() { - echo "path:localpath:${LOCAL_DATA_FOLDER}" -} \ No newline at end of file diff --git a/squashkiwi/backup.sh b/squashkiwi/backup.sh deleted file mode 100755 index bcdfd52..0000000 --- a/squashkiwi/backup.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "CONTAINER_NAME" "LOCAL_DATA_FOLDER" "BACKUP_FILE" "TEMP_DIR" - -# Stop container before backup -_stop_container "$CONTAINER_NAME" - -# shellcheck disable=SC2046 -backup_items $(get_squashkiwi_paths) || _die "Failed to create backup" - -# Start container after backup -_start_container "$CONTAINER_NAME" - -echo "Backup created successfully" diff --git a/squashkiwi/config/.template_info.env b/squashkiwi/config/.template_info.env deleted file mode 100644 index f7c0c02..0000000 --- a/squashkiwi/config/.template_info.env +++ /dev/null @@ -1,21 +0,0 @@ -# DO NOT EDIT THIS FILE FOR YOUR SERVICE! -# This file is replaced from the template whenever there is an update. -# Edit the service.env file to make changes. - - -# Template to use - always required! -TEMPLATE=squashkiwi -REQUIRES_HOST_ROOT=false -REQUIRES_DOCKER=true -REQUIRES_DOCKER_ROOT=true - -# Application settings -CONTAINER_PORT=8181 - -# Deployment settings -CONTAINER_NAME="squashkiwi" - -# Image settings -IMAGE_REGISTRY="gitea.jde.nz" -IMAGE_REPO="squashkiwi/squashkiwi" -IMAGE_TAG="latest" diff --git a/squashkiwi/config/service.env b/squashkiwi/config/service.env deleted file mode 100644 index bd27061..0000000 --- a/squashkiwi/config/service.env +++ /dev/null @@ -1,9 +0,0 @@ -# Service settings specific to this server -# (can also override anything in the .template_info.env file in the template to make it specific to this server) - -HOST_PORT=8181 -LOCAL_DATA_FOLDER="/home/dropshell/example-squashkiwi" -IMAGE_TAG="latest" - -# Server Settings -SSH_USER="root" \ No newline at end of file diff --git a/squashkiwi/destroy.sh b/squashkiwi/destroy.sh deleted file mode 100755 index b7658d1..0000000 --- a/squashkiwi/destroy.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "LOCAL_DATA_FOLDER" - -./uninstall.sh - -# shellcheck disable=SC2046 -destroy_items $(get_squashkiwi_paths) || _die "Failed to destroy ${LOCAL_DATA_FOLDER}" - -echo "Destroyed ${CONTAINER_NAME}" - diff --git a/squashkiwi/install.sh b/squashkiwi/install.sh deleted file mode 100755 index 0b32050..0000000 --- a/squashkiwi/install.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "IMAGE_REGISTRY" "IMAGE_REPO" "IMAGE_TAG" "CONTAINER_NAME" "LOCAL_DATA_FOLDER" - -# shellcheck disable=SC2046 -create_items $(get_squashkiwi_paths) || _die "Failed to create local data folder" - -# Test Docker -_check_docker_installed || _die "Docker test failed, aborting installation..." - -# check can pull image on remote host and exit if fails -docker pull "$IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" || _die "Failed to pull image $IMAGE_REGISTRY/$IMAGE_REPO:$IMAGE_TAG" - -# remove and restart, as the env may have changed. -bash ./stop.sh || _die "Failed to stop container ${CONTAINER_NAME}" -_remove_container "$CONTAINER_NAME" || _die "Failed to remove container ${CONTAINER_NAME}" -bash ./start.sh || _die "Failed to start container ${CONTAINER_NAME}" - -echo "Installation of ${CONTAINER_NAME} complete" diff --git a/squashkiwi/logs.sh b/squashkiwi/logs.sh deleted file mode 100755 index 850702d..0000000 --- a/squashkiwi/logs.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" - -echo "Container ${CONTAINER_NAME} logs:" - -docker logs "${CONTAINER_NAME}" diff --git a/squashkiwi/ports.sh b/squashkiwi/ports.sh deleted file mode 100755 index 721e392..0000000 --- a/squashkiwi/ports.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "HOST_PORT" - -echo $HOST_PORT diff --git a/squashkiwi/restore.sh b/squashkiwi/restore.sh deleted file mode 100755 index e0d5d34..0000000 --- a/squashkiwi/restore.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -# shellcheck disable=SC1091 -source "${AGENT_PATH}/common.sh" -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "${SCRIPT_DIR}/_paths.sh" -_check_required_env_vars "CONTAINER_NAME" "LOCAL_DATA_FOLDER" "BACKUP_FILE" "TEMP_DIR" - -# RESTORE SCRIPT -# The restore script is OPTIONAL. -# It is used to restore the service on the server from a backup file. -# It is called with one argument: the path to the backup file. - -# # Stop container before backup -bash ./uninstall.sh || _die "Failed to uninstall service before restore" - -# shellcheck disable=SC2046 -restore_items $(get_squashkiwi_paths) || _die "Failed to restore data folder from backup" - -# reinstall service -bash ./install.sh || _die "Failed to reinstall service after restore" - -echo "Restore complete! Service is running again on port $HOST_PORT with restored website." diff --git a/squashkiwi/ssh.sh b/squashkiwi/ssh.sh deleted file mode 100755 index 58b6eb8..0000000 --- a/squashkiwi/ssh.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" - -if ! _is_container_running "$CONTAINER_NAME"; then - _die "Container ${CONTAINER_NAME} is not running. Can't connect to it." -fi - -echo "Connecting to ${CONTAINER_NAME}..." - -docker exec -it ${CONTAINER_NAME} bash - -echo "Disconnected from ${CONTAINER_NAME}" diff --git a/squashkiwi/start.sh b/squashkiwi/start.sh deleted file mode 100755 index 1240813..0000000 --- a/squashkiwi/start.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" "HOST_PORT" "CONTAINER_PORT" "LOCAL_DATA_FOLDER" "IMAGE_REGISTRY" "IMAGE_REPO" "IMAGE_TAG" - - -DOCKER_RUN_CMD="docker run -d \ - --restart unless-stopped \ - --name ${CONTAINER_NAME} \ - -p ${HOST_PORT}:${CONTAINER_PORT} \ - -v ${LOCAL_DATA_FOLDER}:/skdata \ - ${IMAGE_REGISTRY}/${IMAGE_REPO}:${IMAGE_TAG}" - - -if ! _create_and_start_container "$DOCKER_RUN_CMD" "$CONTAINER_NAME"; then - echo "${DOCKER_RUN_CMD}" - _die "Failed to start container ${CONTAINER_NAME}" -fi - -# Check if the container is running -if ! _is_container_running "$CONTAINER_NAME"; then - _die "Container ${CONTAINER_NAME} is not running" -fi - -echo "Container ${CONTAINER_NAME} started, on port ${HOST_PORT}" diff --git a/squashkiwi/status.sh b/squashkiwi/status.sh deleted file mode 100755 index 1170190..0000000 --- a/squashkiwi/status.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" "HOST_PORT" - -# check if the service is running -_is_container_running $CONTAINER_NAME || _die "Service is not running - did not find container $CONTAINER_NAME." - -# check if the service is healthy -curl -s -X GET http://localhost:${HOST_PORT}/health | grep -q "OK" \ - || _die "Service is not healthy - did not get OK response from /health endpoint." - -echo "Service is healthy" -exit 0 diff --git a/squashkiwi/stop.sh b/squashkiwi/stop.sh deleted file mode 100755 index 173e424..0000000 --- a/squashkiwi/stop.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" - -_stop_container $CONTAINER_NAME || _die "Failed to stop container ${CONTAINER_NAME}" - -echo "Container ${CONTAINER_NAME} stopped" diff --git a/squashkiwi/uninstall.sh b/squashkiwi/uninstall.sh deleted file mode 100755 index 8162e62..0000000 --- a/squashkiwi/uninstall.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -source "${AGENT_PATH}/common.sh" -_check_required_env_vars "CONTAINER_NAME" "LOCAL_DATA_FOLDER" - -# UNINSTALL SCRIPT -# The uninstall script is required for all templates. -# It is used to uninstall the service from the server. -# It is called with the path to the server specific env file as an argument. - -_remove_container "$CONTAINER_NAME" || _die "Failed to remove container ${CONTAINER_NAME}" -_is_container_running "$CONTAINER_NAME" && _die "Couldn't stop existing container" -_is_container_exists "$CONTAINER_NAME" && _die "Couldn't remove existing container" - -echo "Uninstallation of ${CONTAINER_NAME} complete." -echo "Local data folder ${LOCAL_DATA_FOLDER} still in place."