2026-03-14 03:42:20 +01:00
2026-03-13 21:39:34 +01:00
2026-03-15 04:51:06 +01:00
2026-03-15 03:08:16 +01:00
2026-03-12 11:16:12 +01:00
2026-03-14 02:57:13 +01:00
2026-03-15 02:49:09 +01:00
2026-03-13 23:46:14 +01:00
2026-03-09 20:40:16 +01:00
2026-03-13 23:46:14 +01:00
2026-03-15 03:16:27 +01:00
2026-03-15 04:51:06 +01:00

📺 GridTV

A real-time IPTV TV guide, built for Tunarr and any XMLTV/M3U source.

PHP Apache Nginx Docker License


GridTV Preview


🌐 Demo

A public demo instance is available here:

👉 https://guide.demo.johnnybegood.fr/ Health page: https://guide.demo.johnnybegood.fr/health.php Setup page (read only on demo): https://guide.demo.johnnybegood.fr/setup.php

This demo runs with sample XMLTV feeds to showcase the interface.


Features

  • 🎛️ Timeline grid — horizontal EPG-style view with a live "now" indicator
  • 📅 Date in timebar — midnight markers show the day/date so you always know where you are
  • 📱 Responsive — optimized list view on mobile
  • ⏱️ Live progress bar on the currently airing program
  • 🕶️ Past programs automatically dimmed
  • 📋 Hover tooltip — title, synopsis, season/episode, schedule, duration
  • 🎬 Program popup — click any program for full details + IMDb search link
  • 🔗 One-click copy buttons for EPG & M3U URLs in the topbar
  • ▶️ Built-in HLS player — click any channel or live program to watch in a PiP overlay
  • 🔀 HTTP→HTTPS proxy — streams Tunarr over HTTP transparently from an HTTPS page
  • 🎨 Theme system — drop a CSS file in themes/ and it appears in the menu automatically
  • 📡 Multi-EPG sources — configure multiple EPG/M3U sources, switch from the topbar
  • 👤 Personal EPG — optionally let visitors use your instance with their own EPG/M3U URLs (saved in localStorage)
  • 🔍 Search — filter the grid by channel name or program title/synopsis (debounced)
  • Favorites — pin channels to the top of the grid, persisted in localStorage
  • 🌍 i18n — auto-detects browser language, supports EN / FR / ES (add your own in locales/)
  • ⚙️ Re-editable setup — protected by an admin key, no SSH required to update config
  • 🩺 Admin health page — check config, XMLTV, M3U, response times, and metadata coverage
  • 🖨️ 24h printable export — generate a polished daily schedule for PDF/print and PNG export
  • 🧪 Demo mode — drop a .demo file at the project root to expose admin pages safely in read-only mode
  • 🔔 Update notifications — a badge appears in the topbar when a new release is available on GitHub
  • 🔄 Auto-reload EPG every 30 minutes
  • 0️⃣ Zero build tooling — vanilla PHP/JS/CSS, with bundled local assets

🚀 Installation

Requirements

  • A web server running PHP 8.0+ with php-curl and php-xml extensions
  • Apache or Nginx — or just use Docker
  • An EPG source in XMLTV format (e.g. Tunarr, Jellyfin, xTeVe...)
  • (Optional) An M3U playlist — required for the built-in player

git clone https://github.com/Johnnybegood90/GridTV.git
cd GridTV
docker compose up -d

Then open http://localhost:8080 and follow the setup wizard.

Docker stores the generated configuration in ./data/config.json on the host.

To run on a custom port:

PORT=9000 docker compose up -d

To back up or migrate your Docker setup, keep the data/ directory.


Option B — Native PHP host

1. Clone the repo

git clone https://github.com/Johnnybegood90/GridTV.git /var/www/gridtv
cd /var/www/gridtv

2. Set permissions

chmod 775 /var/www/gridtv
chown -R www-data:www-data /var/www/gridtv

3. Install php-curl + php-xml

The built-in player uses proxy.php to relay HTTP streams over HTTPS, and the admin tools parse XMLTV directly. This requires php-curl and php-xml:

# Debian/Ubuntu — adjust version to match your PHP
apt install php8.4-curl php8.4-xml
systemctl reload apache2   # or: systemctl reload nginx

4. Reverse proxy examples

Show reverse proxy / vhost examples

These examples are intentionally minimal. Replace guide.your-domain.com with your domain and adjust the PHP socket or upstream target to match your host.

Nginx + PHP-FPM
server {
    listen 80;
    server_name guide.your-domain.com;

    root /var/www/gridtv;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }
}
nginx -t && systemctl reload nginx

Adjust php8.2-fpm.sock to match the PHP-FPM version installed on your server.

Apache vhost
<VirtualHost *:80>
    ServerName guide.your-domain.com
    DocumentRoot /var/www/gridtv

    <Directory /var/www/gridtv>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>
a2enmod php8.4 rewrite
systemctl reload apache2
Caddy
guide.your-domain.com {
    root * /var/www/gridtv
    php_fastcgi unix//run/php/php8.2-fpm.sock
    file_server
}
systemctl reload caddy

If you use xcaddy or a distro package, keep the same site block and only adapt the PHP-FPM socket path.

Traefik (Docker labels)

Use this if GridTV runs in Docker and Traefik is your front proxy:

services:
  gridtv:
    build: .
    volumes:
      - ./data:/data
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.gridtv.rule=Host(`guide.your-domain.com`)"
      - "traefik.http.routers.gridtv.entrypoints=websecure"
      - "traefik.http.routers.gridtv.tls=true"
      - "traefik.http.services.gridtv.loadbalancer.server.port=80"

You still need a running Traefik instance with websecure configured and DNS pointing to it.

5. First launch — Setup

Open your browser at http://guide.your-domain.com.

GridTV detects the missing config and automatically redirects you to the setup page:

Field Description
Group name Displayed top-left in the topbar
EPG sources Add one or more XMLTV sources, each with an optional M3U URL
Personal EPG Toggle to allow visitors to use your instance with their own EPG/M3U

Once submitted, config.json is created on the server. The setup page becomes inaccessible until you re-enter your admin key.

Admin tools are available here once unlocked with the same key:

http://guide.your-domain.com/health.php
http://guide.your-domain.com/export.php

health.php is admin-only by default. export.php is public so visitors can print or save the daily guide.


Editing the config later

Editing the config later

You can re-open the setup page at any time using the admin key generated during first setup:

http://guide.your-domain.com/setup.php

Enter your admin key to unlock the configuration form. The key is stored in config.json under admin_key — if you lose it, you can retrieve it there via SSH.

Or edit config.json directly:

nano /var/www/gridtv/config.json
{
  "group_name": "MyGroup TV",
  "epg_sources": [
    {
      "name": "Main",
      "epg_url": "http://192.168.0.3:8000/api/xmltv.xml",
      "m3u_url": "http://192.168.0.3:8000/api/channels.m3u"
    },
    {
      "name": "Sports",
      "epg_url": "http://192.168.0.3:8001/api/xmltv.xml",
      "m3u_url": ""
    }
  ],
  "allow_personal_epg": true
}

Instances running the old single-source format (epg_url at root) are migrated automatically on first load.


Health page

🩺 Health page

The health page gives you a quick operational view of your instance without needing SSH first:

  • checks whether config.json exists and is writable by PHP
  • shows the current PHP version and whether php-curl / php-xml are loaded
  • tests each configured XMLTV source
  • tests each configured M3U playlist when present
  • shows response times, final URL after redirects, content type, and basic metadata counts
  • highlights XMLTV coverage for things like category, sub-title, rating, and date

By default, the page is protected by the same admin key as setup.php:

http://guide.your-domain.com/health.php

If you enable demo mode with a .demo file, visitors can open the page without the key.


24h export

🖨️ 24h export

The export page builds a printable 24-hour TV guide from the current XMLTV source:

  • filter by source
  • choose the target date
  • restrict the export to a time window (00h-24h, morning, afternoon, evening, prime time)
  • limit the number of visible channels
  • choose between a readable card layout or a dense timeline
  • export to PDF via the browser print dialog
  • export to PNG directly from the page

Public URL:

http://guide.your-domain.com/export.php

This page is intentionally public so you can share a “TV guide sheet” with other people.


Demo mode

🧪 Demo mode

If you want to expose your instance publicly without letting visitors modify it, create an empty .demo file at the project root:

touch /var/www/gridtv/.demo

When .demo exists:

  • setup.php becomes read-only
  • health.php can be viewed without entering the admin key
  • visitors can inspect the current configuration safely

To disable demo mode:

rm /var/www/gridtv/.demo

.demo is ignored by Git, just like config.json.


Project structure

📁 Project structure

gridtv/
├── index.php            # Entry point
├── setup.php            # Setup + re-configuration (admin key protected)
├── health.php           # Admin diagnostics page
├── export.php           # 24h printable export (PDF/image friendly)
├── proxy.php            # HTTP→HTTPS stream proxy
├── version.json         # Current version (used for update check)
├── Dockerfile
├── docker-compose.yml
├── .gitignore           # local instance files excluded
├── locales/             # i18n translation files
│   ├── en.json
│   ├── fr.json
│   └── es.json
├── themes/              # CSS theme files
│   ├── default.css
│   ├── magazine.css
│   ├── cyberpunk.css
│   └── steampunk.css
└── src/
    ├── config.php       # Config loader, migration, locale detection
    ├── css/             # CSS modules (one file per feature)
    │   ├── base.css     # Variables, reset, global layout
    │   ├── topbar.css   # Topbar, nav, source switcher, theme selector
    │   ├── grid.css     # Grid, channels, programs, ruler, tooltip, loading
    │   ├── mobile.css   # Mobile list view
    │   ├── player.css   # HLS PiP player
    │   ├── modals.css   # Personal EPG modal
    │   ├── search.css   # Search bar + highlight
    │   ├── program.css  # Program info modal + midnight marker
    │   ├── favorites.css# Favorite button + separator
    │   └── updater.css  # Update notification badge
    ├── tpl/             # HTML templates
    │   ├── head.php     # DOCTYPE, <head>, includes CSS modules
    │   ├── topbar.php   # Topbar (nav, source switcher, search, theme)
    │   ├── grid.php     # Grid + mobile + PiP + overlays
    │   ├── modals.php   # Program info modal + Personal EPG modal
    │   └── footer.php   # JS modules loader, </body></html>
    └── js/              # JavaScript modules (one file per feature)
        ├── config.js    # Constants + PHP-injected vars (incl. locale)
        ├── utils.js     # Helpers, clock, EPG fetch
        ├── epg.js       # Grid rendering
        ├── mobile.js    # Mobile list view
        ├── tooltip.js   # Hover tooltip
        ├── sources.js   # Multi-EPG switcher + Personal EPG
        ├── m3u.js       # M3U parser
        ├── player.js    # HLS PiP player
        ├── themes.js    # Theme switcher
        ├── search.js    # Search + filter (debounced)
        ├── program.js   # Program info modal + IMDb link
        ├── favorites.js # Favorites (localStorage)
        ├── updater.js   # GitHub update checker
        └── live.js      # Live updates + responsive

config.json is listed in .gitignore — your private URLs will never be pushed to GitHub.


Themes

🎨 Themes

GridTV ships with 4 built-in themes. To add your own, create a CSS file in themes/ with these metadata comments at the top:

/*
 * @name  My Theme
 * @emoji 🌙
 */

:root {
  --bg: #0a0b0d;
  --accent: #e8c842;
}

Drop it in themes/ — it appears in the theme selector automatically.


Multiple EPG Sources

📡 Multiple EPG Sources

Configure as many EPG/M3U sources as you want in config.json. A dropdown appears in the topbar when more than one source is defined.

If allow_personal_epg is true, a "✏ Personal EPG" option appears in the dropdown, letting any visitor enter their own XMLTV/M3U URLs. Their choice is saved in localStorage — zero server impact.


Built-in Player

▶️ Built-in Player

Click on any channel name or currently airing program to open a PiP player in the bottom-right corner.

Requires an M3U URL in the active source and the php-curl extension. The proxy.php handles HTTP→HTTPS relay transparently.


Advanced configuration

⚙️ Advanced configuration

Tweak these constants in src/js/config.js:

const PX_PER_MIN = 5;    // Horizontal zoom (pixels per minute)
const GRID_HOURS = 72;   // Total timeline duration (hours)
const ROW_H      = 80;   // Channel row height (px)

EPG Compatibility

🧩 EPG Compatibility

GridTV parses the standard XMLTV format. Tested with:


Internationalization

🌍 Internationalization

GridTV auto-detects the visitor's browser language and serves the matching locale. Supported out of the box: English, French, Spanish.

To add a new language, create a file in locales/ based on an existing one:

cp locales/en.json locales/de.json
# then translate the values

GridTV will automatically pick it up for browsers with that language set — no code changes needed.


Contributing

🤝 Contributing

PRs are welcome! Got an idea, a fix, or a feature request — open an issue or send a PR.


License

📄 License

GNU Affero General Public License v3.0 (AGPLv3)


Roadmap

🗺️ Roadmap

Done

  • Timeline grid with live "now" indicator
  • Mobile responsive list view
  • Built-in HLS PiP player
  • HTTP→HTTPS proxy
  • Theme system (4 built-in themes)
  • Multi-EPG sources with topbar switcher
  • Personal EPG (localStorage)
  • Modular codebase (src/tpl + src/js + src/css)
  • Docker support
  • Search — filter grid by channel name or program title/synopsis (debounced)
  • Date in timebar — midnight markers with day/date in the ruler
  • Program popup — full details + IMDb search link on any program click
  • i18n — EN / FR / ES with browser auto-detection, extensible via locales/
  • Favorites — pin channels to the top of the grid (localStorage)
  • Setup re-editable — protected by an admin key, auto-generated on first setup
  • Admin health page — diagnostics for config, XMLTV, M3U, timing, and metadata coverage
  • Update notifications — topbar badge links to latest GitHub release

🔜 Coming soon

  • Dark/Light auto mode — follow system preference when using the default theme
S
Description
Real-time IPTV TV guide and any XMLTV/M3U source. Self-hosted, zero dependencies.
Readme AGPL-3.0
6.5 MiB
Languages
PHP 52.3%
JavaScript 28.8%
CSS 18.5%
Dockerfile 0.3%
Shell 0.1%