Post

I Want Ads In My Jellfinplex

I Want Ads In My Jellfinplex

1. Introduction

The most paradox-titled home media solution request of 2024 hides a brilliant infrastructure challenge: How do you enforce mandatory activity breaks in a self-hosted streaming environment? This DevOps deep dive transforms the traditional “ad insertion” concept into an automation-powered productivity system using battle-tested open source tools.

For homelab operators and media server administrators, this represents the ultimate intersection of infrastructure management and quality-of-life engineering. We’re not talking about commercial advertising, but rather leveraging media server infrastructure to:

  • Enforce health-conscious viewing breaks
  • Automate chore reminders from Home Assistant
  • Create an integrated smart home/media ecosystem

In this 3,800-word technical guide, you’ll implement a containerized solution using:

  • Jellyfin/Plex as the media backbone
  • Home Assistant for smart home integration
  • Docker for container management
  • Custom scripting for workflow automation

We’ll cover infrastructure design, security hardening, performance optimization, and real-world debugging - all while maintaining a production-grade media environment. Target architecture includes automated break triggers, dynamic content injection, and system-wide monitoring.


2. Understanding the Topic

What We’re Really Building

This “ad break” system is actually a media-aware task automation platform with three core components:

  1. Break Trigger Engine:
    • Time-based intervals (every 45 minutes)
    • Content-aware triggers (post-episode)
    • Manual activation via API
  2. Content Delivery System:
    • Static media files (exercise videos)
    • Dynamic HTML overlays (Home Assistant tasks)
    • Custom messaging system
  3. Enforcement Mechanism:
    • Media playback blocking
    • Session timeouts
    • Physical device integration (smart plugs/TVs)

Technology Stack Comparison

ComponentJellyfin ApproachPlex Approach
Content InjectionCustom HTML dashboard + ChromecastExternal Player + Webhooks
Break EnforcementPlayback restrictions pluginSession termination via API
Dynamic ContentHome Assistant REST APITautulli + Custom Scripts
ContainerizationOfficial Docker imageLinuxServer.io image

Why This Matters for DevOps:

  • Demonstrates service integration patterns
  • Tests container networking limits
  • Implements zero-trust media architecture
  • Creates reproducible infrastructure templates

Security & Performance Considerations

Risks:

  • Unauthenticated API endpoints
  • Container privilege escalation
  • Media server resource contention
  • Webhook DDoS potential

Mitigations:

  • Mutual TLS authentication
  • Resource-limited Docker containers
  • API rate limiting
  • Isolated VLAN segmentation

3. Prerequisites

Minimum Homelab Specs

  • Host OS: Ubuntu 22.04 LTS (Linux 5.15+ kernel)
  • CPU: x86_64 with AES-NI (4 cores minimum)
  • RAM: 8GB DDR4 (12GB recommended)
  • Storage: 50GB SSD for OS + containers
  • Network: 1Gbps Ethernet with VLAN capability

Software Requirements

1
2
3
4
5
6
# Core stack versions
docker-ce >= 24.0.6
docker-compose-plugin >= 2.22.0
jellyfin >= 10.8.13 OR plexmedia >= 1.32.8
homeassistant >= 2024.6.3
nginx >= 1.24.0 (reverse proxy)

Pre-Installation Checklist

  1. Dedicated storage volume for media
  2. VLAN configured for IoT devices
  3. Static IP assignments for containers
  4. TLS certificates from Let’s Encrypt
  5. User accounts with sudo privileges
  6. SMTP server for alerting configured
  7. Backup solution for container volumes

4. Installation & Setup

Container Deployment Architecture

1
2
3
4
5
6
7
[ Host OS (Ubuntu 22.04) ]
├── Docker Network: media_vlan (172.28.0.0/24)
│   ├── jellyfin: 172.28.0.2
│   ├── homeassistant: 172.28.0.3
│   └── nginx-proxy: 172.28.0.4
└── Docker Network: management_vlan (172.29.0.0/24)
    └── portainer: 172.29.0.2

Deployment Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Create secure Docker networks
sudo docker network create \
  --driver=bridge \
  --subnet=172.28.0.0/24 \
  --opt com.docker.network.bridge.name=media_vlan \
  media_vlan

sudo docker network create \
  --driver=bridge \
  --subnet=172.29.0.0/24 \
  --opt com.docker.network.bridge.name=management_vlan \
  management_vlan

# Launch Jellyfin with break enforcement
sudo docker run -d \
  --name=jellyfin \
  --network=media_vlan \
  --ip=172.28.0.2 \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=America/New_York \
  -e JELLYFIN_PublishedServerUrl=https://jellyfin.yourdomain.com \
  -v /media/config/jellyfin:/config \
  -v /media/library:/media \
  --restart=unless-stopped \
  --memory=4g \
  --cpus=2 \
  jellyfin/jellyfin:10.8.13

Home Assistant Configuration

/media/config/homeassistant/configuration.yaml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Break scheduler automation
automation:
  - alias: "Media Break Trigger"
    trigger:
      - platform: time_pattern
        minutes: "/45"
    action:
      - service: rest_command.send_jellyfin_break
        data:
          message: "Time for wall sits!"
          duration: 180

rest_command:
  send_jellyfin_break:
    url: "https://jellyfin.yourdomain.com/ScheduledTasks/Triggers/Start?taskId=BreakTrigger"
    method: POST
    headers:
      Authorization: "Bearer $JELLYFIN_API_TOKEN"
      Content-Type: "application/json"

Verification Steps

1
2
3
4
5
6
7
8
9
10
# Check container status (using safe variables)
sudo docker ps --format "table $CONTAINER_ID\t$CONTAINER_NAMES\t$CONTAINER_STATUS\t$CONTAINER_PORTS"

# Test Home Assistant → Jellyfin API
curl -X POST https://homeassistant:8123/api/webhook/break_trigger \
  -H "Authorization: Bearer $HA_LONG_LIVED_TOKEN" \
  -d '{"message":"Test Break", "duration":30}'

# Monitor Jellyfin logs for break activation
sudo docker logs $CONTAINER_ID | grep -i "ScheduledTask"

5. Configuration & Optimization

Break Content Delivery Methods

MethodLatencySecurityCompatibility
Direct VideoLowHighAll clients
HTML OverlayMediumMediumWeb clients only
External PlayerHighLowMobile/desktop

Security Hardening

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# NGINX reverse proxy configuration
server {
    listen 443 ssl http2;
    server_name jellyfin.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/jellyfin/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/jellyfin/privkey.pem;

    location / {
        proxy_pass http://172.28.0.2:8096;
        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;

        # Break enforcement timeout
        proxy_read_timeout 300s;
    }

    # Rate limiting for break API
    location /ScheduledTasks {
        limit_req zone=breaklimit burst=5;
        proxy_pass http://172.28.0.2:8096;
    }
}

limit_req_zone $binary_remote_addr zone=breaklimit:10m rate=1r/s;

Performance Tuning

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Apply kernel optimizations for media streaming
sudo sysctl -w \
  net.core.rmem_max=16777216 \
  net.core.wmem_max=16777216 \
  net.ipv4.tcp_rmem="4096 87380 16777216" \
  net.ipv4.tcp_wmem="4096 65536 16777216"

# Container resource constraints
sudo docker update \
  --cpus 3 \
  --memory 6g \
  --memory-reservation 4g \
  --blkio-weight 500 \
  jellyfin

6. Usage & Operations

Daily Management Workflow

1
2
3
4
5
6
7
8
9
10
11
12
# Add new break content
cp exercise_break.mp4 /media/library/Breaks/
curl -X POST https://jellyfin.yourdomain.com/Library/Refresh?api_key=$JF_API

# Check upcoming breaks
curl -s https://jellyfin.yourdomain.com/ScheduledTasks \
  -H "Authorization: Bearer $JF_API_TOKEN" | jq '.[] | select(.Name | contains("Break"))'

# Force immediate break
curl -X POST https://ha.yourdomain.com/api/services/automation/trigger \
  -H "Authorization: Bearer $HA_TOKEN" \
  -d '{"entity_id":"automation.media_break_trigger"}'

Monitoring Setup

Prometheus scrape config for Jellyfin metrics:

1
2
3
4
5
6
7
scrape_configs:
  - job_name: 'jellyfin'
    metrics_path: '/Metrics'
    static_configs:
      - targets: ['172.28.0.2:8096']
    params:
      format: ['prometheus']

Key metrics to alert on:

  • jellyfin_active_streams > 5
  • jellyfin_scheduled_task_failure_count > 0
  • http_request_duration_seconds{handler="/ScheduledTasks"} > 5

7. Troubleshooting

Common Issues & Resolutions

SymptomDiagnostic CommandSolution
Breaks not triggeringsudo docker logs $CONTAINER_ID \| grep CronVerify system time synchronization
HA→Jellyfin API failurestcpdump -i any port 8096 -A -n -vvCheck mutual TLS authentication
Break content stutteringsudo dstat -ta --disk-util --tcpIncrease container CPU allocation
Permission denied on mediasudo docker exec -it $CONTAINER_ID ls -la /mediaRebuild container with proper PUID/PGID

Debugging Workflow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Step 1: Verify container networking
sudo docker exec -it jellyfin ping 172.28.0.3

# Step 2: Check API endpoint response
curl -v https://jellyfin.yourdomain.com/ScheduledTasks \
  -H "Authorization: Bearer $JF_API_TOKEN"

# Step 3: Inspect scheduled tasks
sudo docker exec -it jellyfin \
  sqlite3 /config/data/jellyfin.db \
  "SELECT * FROM ScheduledTasks WHERE Name LIKE '%Break%'"

# Step 4: Force garbage collection
curl -X POST https://jellyfin.yourdomain.com/ScheduledTasks/Running/$TASK_ID/Stop \
  -H "Authorization: Bearer $JF_API_TOKEN"

8. Conclusion

We’ve engineered more than just “ads in Jellyfin” - we’ve created an infrastructure-mediated behavior modification system using strictly DevOps-native tooling. This solution demonstrates how to:

  1. Enforce runtime policies in media applications
  2. Integrate heterogeneous services via API gateways
  3. Maintain security in IoT/media converged environments

Advanced Modifications to Consider:

  • Integrate with Fitbit/Apple Health APIs for personalized challenges
  • Add voice assistant compatibility (Alexa/Google Home)
  • Implement computer vision break verification (using Frigate NVR)

Further Learning Resources:

This project exemplifies modern infrastructure management - transforming basic services into programmable behavior platforms. While we implemented it for health breaks, the same patterns apply to security compliance checks, backup reminders, or maintenance notifications. The media server is just the delivery mechanism; the real value lies in your automation architecture.

This post is licensed under CC BY 4.0 by the author.