EPG Planer
The EPG Planer is where your team builds the channel's programme schedule: you keep a library of shows, place broadcasts in a weekly grid, and publish the result as XMLTV, JSON and iCalendar feeds for cable networks, websites and apps.
01Getting started
- Log in with the username and initial password you received from your administrator. You can switch the language (DE / EN / IT / FR) at the top of the login window.
- Set your own password. On the first login with an initial password you are asked to choose a personal one (at least 8 characters).
- Find your way around. The planner opens on the current week, scrolled to the current time.
02The screen
| Area | What it shows |
|---|---|
| Top bar | Channel name and logo, the programme On air right now with remaining time and progress, the Next programme and the clock. |
| Toolbar | Today, previous / next, date picker, Day / Week view, the feed links XMLTV JSON ICS, reload ⟳ and + Schedule. |
| Left sidebar | Tab Schedule: the day list on top and the show library (Shows) below, both visible at once. Drag the divider between them to change their size; double-click it to reset. Tab Approvals: pending changes. |
| Grid | The week or day, 00:00–24:00. Every block is one broadcast; the coloured edge is the show colour. Day headers show the number of shows and how much of the day is covered. |
| Editor (right) | Opens when you select or create a broadcast. |
| Status bar | Connection state, number of broadcasts, shortcuts, your name and role, ⚙ Settings, Help and Log out. |
03Roles & approval
Changes need approval
Can plan and edit everything. Changes are saved, but appear in the feeds only after an admin approves them.
Publishes directly
Like an editor, but changes go live immediately. Cannot manage users, settings or approve others.
Full control
Changes go live immediately. Approves or rejects editors' changes, manages users, channel data, feeds and tokens.
Everyone always sees the working version in the planner. The feeds only ever contain the approved version. Items waiting for approval are marked with an amber dot ● and a dashed outline.
04Shows (library)
A show is the reusable template: title and default details. A broadcast is one airing of a show at a specific time. Changing a show updates all its broadcasts.
Create or edit a show
In the Shows list below the day programme, click + New, or click an existing show. The show opens in a window:
| Field | Purpose |
|---|---|
| Title | Name of the show. Must be unique. |
| Subtitle | A fixed second title line, e.g. "The Sunday crime drama". This is not closed captions. |
| Find genre | Type a keyword in any language – e.g. "Krimi", "Tatort", "Schlager", "Jodel", "Kochen", "Wetter" or "cuisine" – and the matching genre and subgenre are suggested with their code. Enter takes the best match, ↑ ↓ choose another. Small typos are tolerated, and several words narrow the search ("film komödie"). Searching alone does not change the show; only picking a result fills Genre and Subgenre. |
| Genre (DVB) | One of the 11 standard DVB main genres, shown with the first digit of its code (e.g. 0x6_ · Music / Dance). Cable networks and receivers use it for genre colours and filters. |
| Subgenre (DVB) | Refines the genre and completes the two-digit DVB code, e.g. 0x63 · Folk / Traditional music or 0x11 · Detective / Thriller. Leave it on …0 · general if nothing fits. Available once a genre is chosen. For Special (0xB_) the subgenre is the actual characteristic, e.g. 0xB3 · Live broadcast. |
| Season (default) | Current season. Broadcasts use it unless they have their own season. |
| Category | Your own free term, e.g. "Schlager", "Volksmusik" or "Magazin". Optional and finer than the DVB genre: shown by receivers as an extra tag and useful for filters on websites and apps. Earlier categories are suggested. Leave it empty if the genre is precise enough. |
| Duration min | Default length when the show is scheduled. |
| Colour | Colour of the show in the grid. |
| Explicit content | Small checkbox below the description. Adults only. Marked in the feeds as explicit and shown with a red E in the library and day programme. |
| Description, Image | Default synopsis and image for all broadcasts. |
A brand-new title typed into a broadcast's Show field also creates a show automatically when you save.
0x61 · Rock / Pop, category "Schlager"; folk music concert = 0x63 · Folk / Traditional music, category "Volksmusik".Archive or delete
- Archive moves a show out of the library and the title suggestions, e.g. when a series has ended. Its broadcasts stay in the schedule and the EPG; if some are still planned, you are asked to confirm.
- Archive (n) in the header of the show list opens the archive. Click a show there and choose Restore, or simply schedule it again: it is restored automatically.
- Delete is only possible when the show has no broadcasts in the EPG period or later. Its past broadcasts are deleted with it. Until then, archive it instead.
05Scheduling broadcasts
There are several ways to put a broadcast into the plan:
| How | Result |
|---|---|
| Drag a show from the Shows list into the grid | Scheduled immediately at the drop position with its default duration. |
| Drag in an empty area of the grid | Opens a new broadcast for exactly the dragged time. |
| Double-click an empty area | New 30-minute broadcast at that time. |
| + Schedule in the toolbar | New broadcast right after the last one of the selected day. |
| Schedule in a show's window | Same, already filled with that show. |
| + fill on a gap in the day list | New broadcast that fills the gap exactly. |
Move a broadcast by dragging it, also to another day. Change its length by dragging its bottom edge. Times snap to your grid (see Grid).
Editing a broadcast
Click a broadcast in the grid or in the day list. The editor on the right shows:
- Show: as soon as you start typing, existing shows are suggested with genre, duration and how often they are scheduled (also archived ones and matches in the category). Pick one with the mouse or ↑ ↓ Enter; its default duration is taken over. A new title can be created directly from the list. ✎ opens the show itself. The hint below shows its default duration, how often it is scheduled and its genre.
- Date, Start, Duration min: the end time is shown below. Start times and durations work in 5-minute steps.
- Recurrence: see Recurring series.
- This broadcast: details for this airing only. Leave a field empty to use the show's value (shown greyed out).
- Season, Episode: published as e.g.
S12E05. - Subtitle / episode title, Description, Image.
- Season, Episode: published as e.g.
Save (Ctrl+S) stores the broadcast. Duplicate creates a copy directly after it, with the episode number increased by one. Delete asks for confirmation (click twice).
Recurring series
Set Recurrence to turn a broadcast into a series:
| Option | Settings |
|---|---|
| None | Single broadcast. |
| Daily | Every day, or every n days. |
| Monday – Friday | Every working day. |
| Weekly | Selected weekdays, every n weeks. |
Optionally set Until to end the series. Series broadcasts show ↻.
When you change, move or delete a broadcast that belongs to a series, you are asked what the change applies to:
| Choice | Effect |
|---|---|
| This broadcast only | Only this airing changes; the rest of the series stays. The editor notes "this broadcast is customised". |
| This and all following | The series is split: earlier broadcasts stay as they were, this one and all later ones change. |
| All broadcasts in the series | The whole series changes, including past airings. |
Images
Click the image area, drag a file onto it or paste with Ctrl+V. JPG, PNG, WebP and GIF are accepted.
A broadcast without its own image uses the show's image; it is shown faded with the label from show.
06Day programme, gaps & overlaps
The Schedule tab lists the selected day in order. Click a day header in the grid to select another day.
- Gap Empty time of 5 minutes or more. Click + fill to schedule into it.
- Overlap Two broadcasts at the same time, shown with a red dashed outline. Overlaps are allowed but usually a mistake.
- missing: Description, Image marks broadcasts whose EPG details are incomplete.
Past broadcasts are dimmed; the one on air is highlighted in red.
07Approvals
Changes by editors who need approval are collected in the Approvals tab. The badge shows how many are open.
- Each entry shows what is New, Changed or Deleted, which fields changed, the previous state, who made the change and when.
- Admins click ✓ Approve or ✕ Reject per entry, or Approve all / Reject all.
- Approve publishes the change to the feeds. A new show needed by a broadcast is approved with it.
- Reject restores the last approved version in the planner.
08EPG output (feeds)
The links XMLTV JSON ICS in the toolbar open the current feeds. While you are logged in they work without a token.
Partners receive their own link with an access token (see EPG output settings). Send them the Feed Guide; it explains the formats, fields and date filters such as ?date=2026-10-20.
Only approved data appears in the feeds.
- XMLTV follows the official XMLTV standard. Empty fields are left out, so receivers such as TVHeadend, Plex or Enigma2 read it without problems.
- Genres are sent with their official English name, translated into every channel language (German, French, Italian) and with the full DVB code (e.g.
0x63). The channel languages are set in EPG output settings. - Only fields you have filled in are sent: no description, no image or no season simply means that element is missing in XMLTV.
09Settings
Open ⚙ Settings in the status bar. Editors see Grid and Users; admins also see EPG output.
Grid
Choose the snap step from 5 to 30 minutes. It applies to dragging, resizing, double-clicking and scheduling, and is saved for your account only. Times typed into the editor can still be any 5-minute step.
EPG output Admin
| Section | Settings |
|---|---|
| Channel |
|
| Feed period | Days back (0–31) and days ahead (1–31) in the default feed. Shows with broadcasts in this period or later cannot be deleted. |
| Public | On: anyone with the link can read the feeds. Off: a token or login is required. |
| Access tokens | Create one token per recipient (e.g. "Cable network", "Website"), then copy its XMLTV / JSON / ICS link or open it with test ↗. Revoke blocks that recipient immediately without affecting others. |
Click Save after changing channel data or the feed period. The logo is saved as soon as it is uploaded.
Users
Your account (everyone): choose the interface language and Change password.
Team Admin:
- + User: enter username, name and role. Turn on Publish without approval if this editor's changes should go live directly. An initial password is generated; pass it on. The user must set their own password at first login.
- Rename a user by clicking the name on their card.
- Switch the role between Editor and Admin, and toggle Publish without approval for editors.
- Reset password sets a new initial password; Delete removes the user.
- At least one admin always remains. You cannot change your own role or delete yourself.
10Keyboard & mouse
| Action | Shortcut |
|---|---|
| Save broadcast or show | Ctrl+S (⌘+S on Mac) |
| Close editor or window | Esc |
| Delete selected broadcast | Del or Backspace (not while typing in a field) |
| New broadcast | Double-click in the grid, or drag across an empty area |
| Move / change length | Drag the block / drag its bottom edge |
| Paste image | Ctrl+V while the editor or show window is open |
Text pasted from websites or Word is cleaned automatically: no HTML, no hidden characters.
11For administrators
- Server: PHP 8.1 or newer with the extensions pdo_sqlite (database) and GD (image conversion). The folders
data/anduploads/must be writable. - Data: everything is stored in the SQLite database
data/epg.sqlite(plus the working filesepg.sqlite-walandepg.sqlite-shm– do not delete them while the planner is running). Only the requested days are loaded, so the planner stays fast however many years of schedule it holds. - Several users at once: any number of people can work and any number of partners can fetch feeds at the same time. Saves are processed one after another, each completely or not at all, so no change is lost. If two people edit the same broadcast at the same moment, the later save wins.
- Backups: once a day, on the first save, a complete copy is written to
data/backup/epg-YYYY-MM-DD.sqlite; the last 14 are kept. To restore, stop access, replacedata/epg.sqlitewith a backup and delete the-wal/-shmfiles. Also back updata/backup/anduploads/to another system regularly. - Update from an older version: an existing
data/epg.jsonis imported automatically on the first request and then renamed toepg.json.imported. The fileepg.lockis no longer needed. - Storage location: keep
data/on a local disk, not on a network share (NFS/SMB), otherwise locking is not reliable. On Apache the folder is protected bydata/.htaccess; on nginx block it in the server configuration, e.g.location /data { deny all; }. - Short feed links (
/epg/<token>.xml) need Apache with mod_rewrite and the fileepg/.htaccess. If they are not available, the planner automatically uses the long form (/epg/?t=…&f=xml). - Defaults such as the initial admin password and time zone are in
config.php. Changeinitial_passwordbefore the first start – the shipped default is publicly known and is refused. - Forgotten admin password: set
'reset_admin' => trueinconfig.php, log in asadminwith theinitial_password, choose a new password, then set it back tofalse.
Security & going live
Built in – nothing to configure:
- Login lock: after 5 wrong passwords for the same username from the same address, that combination is locked for 15 minutes; after 20 wrong attempts from one address, the whole address is locked. Others, including the real admin elsewhere, can still log in.
- Requests from other websites are refused: changes are only accepted from the planner itself (own header and same origin), and the planner cannot be embedded in other pages.
- Security headers on all PHP responses, strict sessions (HttpOnly, SameSite, Secure on HTTPS), passwords stored as bcrypt hashes.
- No internal details in error messages; they go to the PHP error log only.
- Self-check for admins: a red Security notice appears after login if the data folder can be downloaded from the internet, the site runs without HTTPS or
reset_adminis still on. It is re-checked when you open ⚙ Settings → EPG output.
Checklist before going public:
- HTTPS with a valid certificate (e.g. Let's Encrypt).
- Data folder outside the web root – the safest option, independent of the web server. In
config.phpset e.g.'data_dir' => '/var/epg-data'(writable by PHP). If it must stay indata/: on Apache,AllowOverridemust allow the shippeddata/.htaccess; on nginx add the block below. - Change
initial_password, log in, set your own password; keepreset_adminonfalse. - Delete
demo.phpif you do not need demo data. - After login, check that no red Security notice appears.
# nginx: data folder blocked, security headers also for the static pages
location ^~ /data/ { deny all; return 404; }
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "same-origin" always;
add_header Strict-Transport-Security "max-age=31536000" always; # only with HTTPS
Public demo
For a public demo, run a separate installation (e.g. on demo.example.com) and set 'sandbox' => true in its config.php. Every visitor then automatically gets:
- their own empty project with its own database and images – visitors never see each other's data,
- direct login as admin, with the login shown in the Demo bar at the bottom (needed after logging out or to test roles),
- Load demo data fills the project with a complete 24-hour schedule; Start over deletes it and starts a new, empty one,
- working feeds for testing in VLC, TVHeadend etc.: the feed links contain the project ID (
epg/?s=…&f=xml).
After sandbox_ttl (default 1 hour) the project and its images are deleted; the page then starts a new, empty one. Limits against abuse, all in config.php:
| Setting | Default | Meaning |
|---|---|---|
| sandbox_ttl | 3600 | Lifetime of a project in seconds (minimum 300). |
| sandbox_max | 100 | Projects at the same time; further visitors see "Demo is busy". |
| sandbox_per_ip | 5 | Projects at the same time per visitor address. |
| sandbox_uploads | 30 | Images per project (demo images are shared and do not count). |
- Projects are stored in
data/sandbox/<id>/, images inuploads/sb-<id>/; shared demo images inuploads/_demo/. Cleanup runs automatically, no cron job needed. - The demo uses its own login cookie, so it does not interfere with a real planner on the same domain. Keep
demo.phpin the demo installation; it is only reachable from within a project. - The security checklist above applies to the demo too, especially HTTPS and a protected
data/folder.
12Troubleshooting
| Problem | Solution |
|---|---|
| New features or fields are missing after an update | The browser shows cached files. Reload with Ctrl+F5 (Mac: ⌘+Shift+R). |
| "Password is correct, but the login is not kept" | Allow cookies for this site. |
| A change does not appear in the feed | Check the Approvals tab. Changes by editors appear only after approval. |
| A show cannot be deleted | It still has broadcasts in the EPG period or later. Archive it, or delete those broadcasts first. |
| Feed link returns "Not Found" | Short links are not active on the server. Open ⚙ Settings → EPG output once; the planner then switches to the long form automatically. |
| Feed returns "Zugriff verweigert" (access denied) | The token is missing, wrong or revoked, and the feed is not public. |
| "Too many failed attempts – please try again in n minutes" | The login lock is active for this username and address. Wait the stated time; other users are not affected. |
| "Please change initial_password in config.php first" | First start or reset_admin with the shipped default password. Set your own initial_password in config.php. |
| "Request rejected" when saving | The request did not come from the planner page itself, e.g. an old cached app.js. Reload with Ctrl+F5. If the planner runs behind a proxy, it must pass the original Host header. |
| Red Security notice | Follow the text in the notice; see Security & going live. |
| Error "PHP-Erweiterung pdo_sqlite fehlt" | The database extension is not active on the server. Enable pdo_sqlite in the PHP settings or ask your hosting provider. |
| Subgenre list is greyed out | Choose a genre first; the subgenres depend on it. |
| Status bar shows Error | The message next to it names the cause (e.g. folder not writable). Click ⟳ to retry. |