This commit is contained in:
SergeantPanda 2025-03-03 18:55:51 -06:00
commit 063ec0c520
8 changed files with 279 additions and 231 deletions

View file

@ -118,12 +118,11 @@ USE_I18N = True
USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles' # Directory where static files will be collected
STATIC_ROOT = BASE_DIR / 'static' # Directory where static files will be collected
# Adjust STATICFILES_DIRS to include the paths to the directories that contain your static files.
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'frontend/build/static'), # React build static files
BASE_DIR / 'static', # Django custom static files (if any)
]
@ -141,6 +140,7 @@ SERVER_IP = "127.0.0.1"
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_CREDENTIALS = True
CSRF_TRUSTED_ORIGINS = ['*']
APPEND_SLASH = True
REST_FRAMEWORK = {

View file

@ -1,4 +1,4 @@
FROM python:3.13-slim
FROM python:3.13-slim AS builder
ENV PATH="/dispatcharrpy/bin:$PATH" \
VIRTUAL_ENV=/dispatcharrpy \
@ -6,50 +6,73 @@ ENV PATH="/dispatcharrpy/bin:$PATH" \
PYTHONUNBUFFERED=1
RUN apt-get update && \
apt-get install -y \
apt-get install -y --no-install-recommends \
curl \
ffmpeg \
gcc \
git \
gpg \
libpq-dev \
lsb-release \
python3-virtualenv \
streamlink
RUN \
wget && \
echo "=== setting up nodejs ===" && \
curl -sL https://deb.nodesource.com/setup_23.x -o /tmp/nodesource_setup.sh && \
bash /tmp/nodesource_setup.sh && \
curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg && \
chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list && \
apt-get update && \
apt-get install -y redis
RUN apt-get update && \
apt-get install -y \
nodejs \
redis
RUN \
mkdir /data && \
apt-get install -y --no-install-recommends \
nodejs && \
python -m pip install virtualenv && \
virtualenv /dispatcharrpy && \
git clone https://github.com/Dispatcharr/Dispatcharr /app && \
cd /app && \
pip install --no-cache-dir -r requirements.txt && \
pip install --no-cache-dir -r requirements-pytorch.txt && \
pip install --no-cache-dir -r requirements-sentence-transformers.txt && \
python manage.py collectstatic --noinput && \
echo "installing sentence-transformers" && \
pip install sentence-transformers==3.4.1 && \
cd /app/frontend && \
npm install && \
npm run build && \
find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \; && \
cd /app && \
python manage.py collectstatic --noinput || true && \
apt-get remove -y \
gcc \
git \
find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \;
FROM python:3.13-slim
ENV PATH="/dispatcharrpy/bin:$PATH" \
VIRTUAL_ENV=/dispatcharrpy \
DJANGO_SETTINGS_MODULE=dispatcharr.settings \
PYTHONUNBUFFERED=1
# Copy the virtual environment and application from the builder stage
COPY --from=builder /dispatcharrpy /dispatcharrpy
COPY --from=builder /app /app
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ffmpeg \
gnupg2 \
gpg \
libpq-dev \
lsb-release \
nodejs && \
nginx \
procps \
streamlink \
wget && \
cp /app/docker/nginx.conf /etc/nginx/sites-enabled/default && \
echo "=== setting up postgres ====" && \
echo "deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - && \
echo "=== setting up redis ===" && \
curl -fsSL https://packages.redis.io/gpg | gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg && \
chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg && \
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | tee /etc/apt/sources.list.d/redis.list && \
apt-get update && \
apt-get install -y \
postgresql-14 \
postgresql-contrib-14 \
redis-server && \
mkdir /data && \
apt-get remove -y \
gnupg2 \
gpg \
lsb-release && \
apt-get clean && \
apt-get autoremove -y && \
rm -rf \
@ -59,4 +82,4 @@ RUN \
WORKDIR /app
CMD ["/app/docker/entrypoint.aio.sh"]
CMD ["/app/docker/entrypoint.sh"]

View file

@ -1,54 +0,0 @@
FROM alpine
ENV PATH="/dispatcharrpy/bin:$PATH" \
VIRTUAL_ENV=/dispatcharrpy \
DJANGO_SETTINGS_MODULE=dispatcharr.settings \
PYTHONUNBUFFERED=1
RUN apk add \
python3 \
python3-dev \
gcc \
musl-dev \
linux-headers \
py3-pip \
ffmpeg \
streamlink \
vlc \
libpq-dev \
gcc \
py3-virtualenv \
uwsgi \
uwsgi-python \
nodejs \
npm \
git \
redis
RUN \
mkdir /data && \
virtualenv /dispatcharrpy && \
git clone https://github.com/Dispatcharr/Dispatcharr /app && \
cd /app && \
/dispatcharrpy/bin/pip install --no-cache-dir -r requirements.txt && \
cd /app/frontend && \
npm install && \
npm run build && \
find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \; && \
cd /app && \
python manage.py collectstatic --noinput || true
# Cleanup
RUN \
apk del \
nodejs \
npm \
git \
gcc \
musl-dev \
python3-dev \
linux-headers
WORKDIR /app
CMD ["/app/docker/entrypoint.aio.sh"]

View file

@ -1,68 +0,0 @@
FROM python:3.10-slim
ENV API_PORT=5656
# Add PostgreSQL repository
RUN apt-get update && apt-get install -y wget gnupg2 && \
echo "deb http://apt.postgresql.org/pub/repos/apt/ bookworm-pgdg main" > /etc/apt/sources.list.d/pgdg.list && \
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
# Install required packages
RUN apt-get update && apt-get install -y \
ffmpeg \
streamlink \
vlc \
libpq-dev \
gcc \
postgresql-14 \
postgresql-contrib-14 \
redis-server \
npm \
nodejs \
&& rm -rf /var/lib/apt/lists/*
# Set the working directory
WORKDIR /app
# Copy requirements.txt from the parent directory
COPY requirements.txt /app/
# Install Python dependencies
RUN pip install --no-cache-dir -r /app/requirements.txt
# Copy the application source code from the parent directory
COPY . /app/
# Build frontend react
RUN cd /app/frontend && \
npm install && \
npm run build && \
find . -maxdepth 1 ! -name '.' ! -name 'build' -exec rm -rf '{}' \; && \
cd /app && \
python manage.py collectstatic --noinput || true
# Cleanup
RUN apt-get purge -y \
nodejs \
npm \
gcc \
&& apt-get autoremove -y \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set environment variables
ENV DJANGO_SETTINGS_MODULE=dispatcharr.settings
ENV PYTHONUNBUFFERED=1
ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
# Copy the entrypoint script
COPY docker/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
# Expose the port
EXPOSE 9191
# Command to run the startup script
CMD ["/app/entrypoint.sh"]

View file

@ -1,19 +1,18 @@
services:
dispatcharr:
# build:
# context: ..
# dockerfile: docker/Dockerfile.alpine
image: dispatcharr/dispatcharr
# context: .
# dockerfile: Dockerfile
image: dekzter/dispactharr
container_name: dispatcharr
ports:
- 9191:9191
volumes:
- dispatcharr:/data
- dispatcharr_db:/app/data/db
environment:
- DISPATHCARR_ENV=aio
- DB_ENGINE=sqlite
- DISPATCHARR_ENV=aio
- REDIS_HOST=localhost
- CELERY_BROKER_URL=redis://localhost:6379/0
volumes:
dispatcharr:
dispatcharr_db:

View file

@ -1,25 +1,62 @@
#!/bin/sh
#!/bin/bash
set -e # Exit immediately if a command exits with a non-zero status
# Function to clean up only running processes
cleanup() {
echo "🔥 Cleanup triggered! Stopping services..."
for pid in "${pids[@]}"; do
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "⛔ Stopping process (PID: $pid)..."
kill -TERM "$pid" 2>/dev/null
else
echo "✅ Process (PID: $pid) already stopped."
fi
done
wait
}
# Catch termination signals (CTRL+C, Docker Stop, etc.)
trap cleanup TERM INT
# Initialize an array to store PIDs
pids=()
# Function to echo with timestamp
echo_with_timestamp() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1"
}
# Global variables
if [[ ! -f /etc/profile.d/dispatcharr.sh ]]; then
echo "export PATH=$PATH" >> /etc/profile.d/dispatcharr.sh
echo "export VIRTUAL_ENV=$VIRTUAL_ENV" >> /etc/profile.d/dispatcharr.sh
echo "export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE" >> /etc/profile.d/dispatcharr.sh
echo "export PYTHONUNBUFFERED=$PYTHONUNBUFFERED" >> /etc/profile.d/dispatcharr.sh
fi
chmod +x /etc/profile.d/dispatcharr.sh
# Dispatcharr variables
export ADMIN_PORT=5656
# Set PostgreSQL environment variables
export POSTGRES_DB=${POSTGRES_DB:-dispatcharr}
export POSTGRES_USER=${POSTGRES_USER:-dispatch}
export POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secret}
export POSTGRES_HOST=${POSTGRES_HOST:-localhost}
export POSTGRES_PORT=${POSTGRES_PORT:-5432}
export PGDATA=${PGDATA:-/app/data/db}
export PG_BINDIR="/usr/lib/postgresql/14/bin"
# Set up user details
export PUID=${PUID:-1000}
export PGID=${PGID:-1000}
# Set up initial django admin
export DJANGO_SUPERUSER_USERNAME=${DEFAULT_USERNAME:-admin}
export DJANGO_SUPERUSER_PASSWORD=${DEFAULT_PASSWORD:-admin}
export DJANGO_SUPERUSER_EMAIL=${DEFAULT_EMAIL:-admin@dispatcharr.local}
export PGDATA=${PGDATA:-/app/data/db}
export PG_BINDIR="/usr/lib/postgresql/14/bin"
# Echo environment variables for debugging
@ -43,38 +80,86 @@ else
fi
fi
# Initialize PostgreSQL database
if [ -z "$(ls -A "$PGDATA")" ]; then
echo_with_timestamp "Initializing PostgreSQL database..."
mkdir -p "$PGDATA"
chown -R postgres:postgres "$PGDATA"
chmod 700 "$PGDATA"
# If running in development mode, install and start frontend
if [ "$DISPATCHARR_ENV" = "dev" ]; then
echo "🚀 Development Mode - Setting up Frontend..."
# Initialize PostgreSQL
su - postgres -c "$PG_BINDIR/initdb -D $PGDATA"
# Configure PostgreSQL
echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
echo "listen_addresses='*'" >> "$PGDATA/postgresql.conf"
# Install Node.js
apt-get update && apt-get install -y nodejs
# Install frontend dependencies
cd /app/frontend && npm install
cd /app
# Start React development server
echo "🚀 Starting React Dev Server..."
cd /app/frontend
su - $POSTGRES_USER -c "PORT=9191 /app/frontend/node_modules/pm2/bin/pm2 --name dev-server start npm -- start"
./node_modules/pm2/bin/pm2 logs &
react_pid=$(cat /home/dispatch/.pm2/pids/dev-server*)
echo "✅ React started with PID $react_pid"
pids+=("$react_pid")
cd /app
fi
# Start PostgreSQL
su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA start -w -t 300 -o '-c port=${POSTGRES_PORT}'"
# If running in `dev` or `aio`, start Postgres, Redis, and Celery
if [ "$DISPATCHARR_ENV" = "dev" ] || [ "$DISPATCHARR_ENV" = "aio" ]; then
echo "🚀 Running Postgres, Redis, and Celery for '$DISPATCHARR_ENV'..."
# Wait for PostgreSQL to be ready
until su - postgres -c "$PG_BINDIR/pg_isready -h ${POSTGRES_HOST} -p ${POSTGRES_PORT}" >/dev/null 2>&1; do
echo_with_timestamp "Waiting for PostgreSQL to be ready..."
sleep 1
done
# Initialize PostgreSQL database
if [ -z "$(ls -A "$PGDATA")" ]; then
echo_with_timestamp "Initializing PostgreSQL database..."
mkdir -p "$PGDATA"
chown -R postgres:postgres "$PGDATA"
chmod 700 "$PGDATA"
# Setup database if needed
if ! su - postgres -c "psql -p ${POSTGRES_PORT} -tAc \"SELECT 1 FROM pg_database WHERE datname = '$POSTGRES_DB';\"" | grep -q 1; then
# Create PostgreSQL database
echo_with_timestamp "Creating PostgreSQL database..."
su - postgres -c "createdb -p ${POSTGRES_PORT} ${POSTGRES_DB}"
# Initialize PostgreSQL
su - postgres -c "$PG_BINDIR/initdb -D $PGDATA"
# Configure PostgreSQL
echo "host all all 0.0.0.0/0 md5" >> "$PGDATA/pg_hba.conf"
echo "listen_addresses='*'" >> "$PGDATA/postgresql.conf"
fi
# Create user, set ownership, and grant privileges
echo_with_timestamp "Creating PostgreSQL user..."
su - postgres -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB}" <<EOF
# Start Redis
echo "🚀 Starting Redis..."
su - $POSTGRES_USER -c "redis-server --daemonize no &"
sleep 1 # Give Redis time to start
redis_pid=$(pgrep -x redis-server)
if [ -n "$redis_pid" ]; then
echo "✅ Redis started with PID $redis_pid"
pids+=("$redis_pid")
else
echo "❌ Redis failed to start!"
fi
# Start Celery
echo "🚀 Starting Celery..."
su - $POSTGRES_USER -c "cd /app && celery -A dispatcharr worker -l info &"
celery_pid=$(pgrep -x celery)
echo "✅ Celery started with PID $celery_pid"
pids+=("$celery_pid")
# Start PostgreSQL
echo "Starting Postgres..."
su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA start -w -t 300 -o '-c port=${POSTGRES_PORT}'"
# Wait for PostgreSQL to be ready
until su - postgres -c "$PG_BINDIR/pg_isready -h ${POSTGRES_HOST} -p ${POSTGRES_PORT}" >/dev/null 2>&1; do
echo_with_timestamp "Waiting for PostgreSQL to be ready..."
sleep 1
done
postgres_pid=$(su - postgres -c "$PG_BINDIR/pg_ctl -D $PGDATA status" | sed -n 's/.*PID: \([0-9]\+\).*/\1/p')
echo "✅ Postgres started with PID $postgres_pid"
pids+=("$postgres_pid")
# Setup database if needed
if ! su - postgres -c "psql -p ${POSTGRES_PORT} -tAc \"SELECT 1 FROM pg_database WHERE datname = '$POSTGRES_DB';\"" | grep -q 1; then
# Create PostgreSQL database
echo_with_timestamp "Creating PostgreSQL database..."
su - postgres -c "createdb -p ${POSTGRES_PORT} ${POSTGRES_DB}"
# Create user, set ownership, and grant privileges
echo_with_timestamp "Creating PostgreSQL user..."
su - postgres -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB}" <<EOF
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_roles WHERE rolname = '$POSTGRES_USER') THEN
@ -83,52 +168,100 @@ BEGIN
END
\$\$;
EOF
echo_with_timestamp "Setting PostgreSQL user privileges..."
su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"ALTER DATABASE ${POSTGRES_DB} OWNER TO $POSTGRES_USER;\""
su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO $POSTGRES_USER;\""
# Finished setting up PosgresSQL database
echo_with_timestamp "PostgreSQL database setup complete."
fi
echo_with_timestamp "Setting PostgreSQL user privileges..."
su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"ALTER DATABASE ${POSTGRES_DB} OWNER TO $POSTGRES_USER;\""
su postgres -c "$PG_BINDIR/psql -p ${POSTGRES_PORT} -c \"GRANT ALL PRIVILEGES ON DATABASE ${POSTGRES_DB} TO $POSTGRES_USER;\""
# Finished setting up PosgresSQL database
echo_with_timestamp "PostgreSQL database setup complete."
fi
# Test PostgreSQL connection and exit if unavailable
echo_with_timestamp "Testing database connection..."
if ! pg_isready -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB; then
echo_with_timestamp "ERROR: PostgreSQL is not ready. Exiting..."
exit 1
else
echo_with_timestamp "PostgreSQL is ready to accept connections."
fi
# Test PostgreSQL connection and exit if unavailable
echo_with_timestamp "Testing database connection..."
if ! pg_isready -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB; then
echo_with_timestamp "ERROR: PostgreSQL is not ready. Exiting..."
exit 1
else
echo_with_timestamp "PostgreSQL is ready to accept connections."
fi
# Verify database accessibility
echo_with_timestamp "Verifying database accessibility..."
if ! su - $POSTGRES_USER -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB} -c 'SELECT 1;'" >/dev/null 2>&1; then
echo_with_timestamp "ERROR: PostgreSQL is running but the database is not accessible. Exiting..."
exit 1
else
echo_with_timestamp "PostgreSQL database is accessible."
# Verify database accessibility
echo_with_timestamp "Verifying database accessibility..."
if ! su - $POSTGRES_USER -c "psql -p ${POSTGRES_PORT} -d ${POSTGRES_DB} -c 'SELECT 1;'" >/dev/null 2>&1; then
echo_with_timestamp "ERROR: PostgreSQL is running but the database is not accessible. Exiting..."
exit 1
else
echo_with_timestamp "PostgreSQL database is accessible."
fi
fi
# Start Redis
echo_with_timestamp "Starting Redis..."
su - $POSTGRES_USER -c 'redis-server --daemonize yes'
# Run Django commands
cd /app
echo_with_timestamp "Running Django commands..."
python manage.py collectstatic --noinput || true
python manage.py makemigrations --noinput || true
python manage.py migrate --noinput || true
echo_with_timestamp "Checking if Django superuser exists..."
if ! python manage.py shell -c "from django.contrib.auth import get_user_model; exit(0) if get_user_model().objects.filter(username='${DJANGO_SUPERUSER_USERNAME}').exists() else exit(1)"; then
echo_with_timestamp "Superuser does not exist. Creating..."
python manage.py createsuperuser --noinput || true
python manage.py collectstatic --noinput || true
# Always start Gunicorn
echo "🚀 Starting Gunicorn..."
su - $POSTGRES_USER -c "cd /app && gunicorn --workers=4 --worker-class=gevent --timeout=300 --bind 0.0.0.0:${ADMIN_PORT} dispatcharr.wsgi:application &"
gunicorn_pid=$(pgrep -x gunicorn | sort | head -n1)
echo "✅ Gunicorn started with PID $gunicorn_pid"
pids+=("$gunicorn_pid")
echo "🚀 Starting nginx..."
nginx
nginx_pid=$(pgrep nginx | sort | head -n1)
echo "✅ nginx started with PID $nginx_pid"
pids+=("$nginx_pid")
# Log PIDs
echo "📝 Process PIDs: ${pids[*]}"
echo "
%%%%
%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%% %%%%%%%%%%
%%%%% %%%%%%%%%%
@%%%% %%%%%%%%%%
%%%% * %%%%%%%%%%
%%%% **** %%%%%%%%%%
%%%% ******* %%%%%%%%
%%%% *********** %%%%%%
%%%% ************** %%%%
%%%% ************* %
%%%% ********** @%%% %
%%%% ******* %%%%%%
%%%% **** %%%%%%%%%%
%%%% %%%%%%%%%%
%%%% %%%%%%%%%%
%%%% %%%%%%%%%
%%%% %%%%%%%%%@
%%%%%%%%%
@%%%%%%%%%%
%%%%
DISPACTHARR HAS SUCCESSFULLY STARTED
"
# Wait for at least one process to exit and log the process that exited first
if [ ${#pids[@]} -gt 0 ]; then
echo "⏳ Waiting for processes to exit..."
while kill -0 "${pids[@]}" 2>/dev/null; do
sleep 1 # Wait for a second before checking again
done
echo "🚨 One of the processes exited! Checking which one..."
for pid in "${pids[@]}"; do
if ! kill -0 "$pid" 2>/dev/null; then
process_name=$(ps -p "$pid" -o comm=)
echo "❌ Process $process_name (PID: $pid) has exited!"
fi
done
else
echo_with_timestamp "Superuser already exists. Skipping creation."
echo "❌ No processes started. Exiting."
exit 1
fi
# Start Celery
echo_with_timestamp "Starting Celery..."
su - $POSTGRES_USER -c 'cd /app && celery -A dispatcharr worker --loglevel=info &'
# Start Gunicorn
echo_with_timestamp "Starting Gunicorn..."
su - $POSTGRES_USER -c 'cd /app && gunicorn --workers=4 --worker-class=gevent --timeout=300 --bind 0.0.0.0:9191 dispatcharr.wsgi:application'
# Cleanup and stop remaining processes
cleanup

15
docker/nginx.conf Normal file
View file

@ -0,0 +1,15 @@
server {
listen 9191;
server_name yourdomain.com;
location /static/ {
root /app; # Base directory for static files
}
location / {
proxy_pass http://127.0.0.1:5656;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

View file

@ -24,7 +24,7 @@ import {
SwapVert as SwapVertIcon,
LiveTv as LiveTvIcon,
ContentCopy,
Tv as TvIcon, // <-- ADD THIS IMPORT
Tv as TvIcon, // <-- ADD THIS IMPORT
} from '@mui/icons-material';
import API from '../../api';
import ChannelForm from '../forms/Channel';
@ -104,7 +104,7 @@ const ChannelsTable = () => {
};
function handleWatchStream(channelNumber) {
showVideo(`/output/stream/${channelNumber}/`);
showVideo(`http://192.168.1.151:5656/output/stream/${channelNumber}/`);
}
// (Optional) bulk delete, but your endpoint is @TODO