Schedules-Direct-XMLTV

Schedules-Direct-XMLTV

Docker app from heroeswearkapes Community Apps' Repository

Overview

Schedules Direct XMLTV automatically downloads TV guide data from Schedules Direct, converts it to XMLTV format, refreshes the guide on a schedule, and serves the resulting tvxml.xml file over HTTP. Designed for use with Threadfin, Jellyfin, Plex, Emby, TVHeadend, and other applications that accept an XMLTV guide URL. Supports first-run setup mode so a lineup ID does not need to be known before installation. Supports both amd64 and arm64 Docker hosts.

Schedules Direct XMLTV

A lightweight Docker service that automatically fetches TV guide data from Schedules Direct, converts it to XMLTV format, keeps it updated on a schedule, and serves the resulting XMLTV file over HTTP.

This is particularly useful for providing Schedules Direct guide data to applications such as:

  • Threadfin
  • Jellyfin
  • Plex
  • Emby
  • TVHeadend
  • Other applications that accept an XMLTV URL

Features

  • Automatically downloads TV listings from Schedules Direct
  • Converts Schedules Direct data to XMLTV
  • First-run setup mode for discovering Schedules Direct lineups
  • No lineup ID required before initial installation
  • Performs an initial guide download when a lineup is configured
  • Automatically refreshes guide data every day
  • Serves tvxml.xml using nginx
  • Configurable Schedules Direct lineups
  • Supports multiple comma-separated lineups
  • Configurable number of guide days to download
  • Configurable timezone
  • Persistent XMLTV data
  • Docker Compose support
  • Unraid Community Applications support
  • Multi-architecture Docker images
    • linux/amd64
    • linux/arm64

Docker Image

The current image is:

heroeswearkapes/schedules-direct-xmltv:latest

During the migration period, the same image is also published under the legacy repository:

heroeswearkapes/schedules-direct-update-and-serve:latest

New installations should use:

heroeswearkapes/schedules-direct-xmltv

Requirements

You will need:

  • Docker or Docker Compose
  • A valid Schedules Direct subscription

Schedules Direct credentials are provided to the container at runtime and are not stored in the Docker image.

You do not need to know your Schedules Direct lineup ID before installing the container.

If SD_LINEUPS is left blank, the container starts in setup mode so you can discover and add a lineup using the included Schedules Direct configuration wizard.

Quick Start

Clone the repository:

git clone https://github.com/heroeswearkapes/schedules-direct-xmltv.git
cd schedules-direct-xmltv

Create your runtime configuration:

cp .env.example .env

Edit .env:

nano .env

At minimum, configure your Schedules Direct credentials:

SCHEDULES_DIRECT_USERNAME=your_schedules_direct_username
SCHEDULES_DIRECT_PASSWORD=your_schedules_direct_password

If you already know your Schedules Direct lineup ID, you can also configure:

SD_LINEUPS=USA-OTA-10001

If you do not know your lineup ID yet, leave it blank:

SD_LINEUPS=

Then start the container:

docker compose up -d

If SD_LINEUPS is blank, the container will start in setup mode. See First-Time Setup: Finding Your Schedules Direct Lineup below.

Docker Compose

The included docker-compose.yaml uses:

services:
  xmltv:
    image: heroeswearkapes/schedules-direct-xmltv:latest
    container_name: schedules-direct-xmltv

    environment:
      SD_USERNAME: ${SCHEDULES_DIRECT_USERNAME}
      SD_PASSWORD: ${SCHEDULES_DIRECT_PASSWORD}
      SD_LINEUPS: ${SD_LINEUPS:-}
      SD_FETCH_DAYS: ${SD_FETCH_DAYS:-2}
      TZ: ${TZ:-America/New_York}

    ports:
      - "${XMLTV_PORT:-51969}:80"

    volumes:
      - xmltv_data:/var/www/html

    restart: unless-stopped

volumes:
  xmltv_data:

Configuration

The public .env.example contains all runtime options required by Docker Compose.

Schedules Direct Username

SCHEDULES_DIRECT_USERNAME=your_schedules_direct_username

Your Schedules Direct account username.

Schedules Direct Password

SCHEDULES_DIRECT_PASSWORD=your_schedules_direct_password

Your Schedules Direct account password.

Schedules Direct Lineups

Schedules Direct lineup IDs are supplied using SD_LINEUPS.

If you already know your lineup ID:

SD_LINEUPS=USA-OTA-10001

Multiple lineups may be supplied as a comma-separated list:

SD_LINEUPS=USA-OTA-10001,USA-YOUTUBE-X

If you do not know your lineup ID yet, leave the value blank:

SD_LINEUPS=

The container will start in setup mode instead of attempting to download guide data.

While in setup mode:

  • The container remains running.
  • nginx remains available.
  • The initial XMLTV synchronization is skipped.
  • Scheduled synchronization through cron is disabled.
  • The Schedules Direct configuration wizard can be used to discover or add a lineup.

Once a lineup ID is configured and the container is restarted, normal XMLTV synchronization begins automatically.

First-Time Setup: Finding Your Schedules Direct Lineup

With the newer Schedules Direct SD-JSON service, you do not need to obtain a lineup ID from the Schedules Direct website before installing the container.

If you don't know your lineup ID, leave:

SD_LINEUPS=

and start the container.

The logs should indicate:

[INFO] No Schedules Direct lineup configured.
[INFO] Starting in setup mode.
[INFO] Initial XMLTV synchronization skipped.
[INFO] Cron disabled while running in setup mode.

You can monitor the logs with:

docker logs -f schedules-direct-xmltv

1. Start the Schedules Direct Configuration Wizard

For a standard Docker Compose installation:

docker exec -it schedules-direct-xmltv \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

For Unraid, the default container name is:

Schedules-Direct-XMLTV

Run:

docker exec -it Schedules-Direct-XMLTV \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

2. Accept the Default Cache File

The first prompt will look similar to:

Cache file for lineups, schedules and programs.
Cache file: [/root/.xmltv/tv_grab_zz_sdjson.cache]

Press Enter to accept the default cache-file location.

The prompt may appear to be waiting without explicitly telling you to continue. This is normal. Press Enter to proceed.

3. Select the Channel ID Format

You will be asked:

Select channel ID format:
0: Default Format (eg: I12345.json.schedulesdirect.org)
1: tv_grab_na_dd Format (eg: I12345.labs.zap2it.com)
2: MythTV Internal DD Grabber Format (eg: 12345)
Select one: [0,1,2 (default=0)]

For a normal new installation, press Enter to use option 0.

4. Select the Previously Shown Format

The next prompt is:

Select previously shown format:
0: Date Only
1: Date And Time
Select one: [0,1 (default=0)]

For a normal installation, press Enter to use Date Only.

5. Enter Your Schedules Direct Credentials

The wizard will request your Schedules Direct username and password.

It will then authenticate with the Schedules Direct SD-JSON service and retrieve the lineups currently enabled for your account.

6. Add or Manage Account Lineups

The wizard will display any lineups currently enabled for your Schedules Direct account.

For example:

Current lineups enabled for your Schedules Direct account:

#. Lineup ID       | Name                     | Location | Transport
1. USA-OTA-10001   | Local Broadcast Listings | 10001    | Antenna

You will then see:

Edit account lineups: [continue,add,delete (default=continue)]

If the lineup you need is already listed, press Enter to continue.

If you need to find or add a lineup, enter:

add

7. Search for a Lineup

The wizard asks:

Lineup ID or Country (ISO-3166-1 alpha 3 such as USA or CAN):

If you already know a lineup ID, you may enter it directly.

If you do not know it, enter your three-letter country code.

For the United States:

USA

For Canada:

CAN

For this example:

USA

The wizard will query Schedules Direct and then ask for your ZIP or postal code:

Zip Code:

For this example:

10001

Schedules Direct will return the available providers and lineups for that location.

For example:

#. Lineup ID          | Name                       | Location | Transport
1. USA-0000001-CUSTOM | ChannelsDVR TV-Everywhere | National | IPTV
...
37. USA-OTA-10001     | Antenna                    | 10001    | Antenna

The actual list will depend on your location and available television providers.

Select the number corresponding to the lineup you want.

For this example:

37

This adds:

USA-OTA-10001

to the Schedules Direct account.

8. Continue After Adding the Lineup

After adding a lineup, the wizard returns to the list of currently enabled account lineups.

The newly added lineup should now appear.

At:

Edit account lineups: [continue,add,delete (default=continue)]

press Enter to continue.

9. Select Lineup Mode

The wizard asks:

Select mode: [lineups,channels (default=lineups)]

Press Enter to use complete lineups.

This matches the SD_LINEUPS configuration used by this container.

10. Select the Lineup

The wizard will ask which enabled lineup or lineups should be used for the configuration.

For example:

USA-OTA-10001 [yes,no,all,none (default=no)]

Enter:

yes

If additional lineups are enabled on your account, the wizard may ask about each one individually.

11. Configure SD_LINEUPS

You now know the lineup ID required by the container.

For the example above:

USA-OTA-10001

Update your Docker Compose .env file:

SD_LINEUPS=USA-OTA-10001

For multiple lineups:

SD_LINEUPS=USA-OTA-10001,USA-YOUTUBE-X

Then recreate the container:

docker compose up -d

For Unraid:

  1. Open the Docker tab.
  2. Edit Schedules Direct XMLTV.
  3. Enter the lineup ID into Schedules Direct Lineups.
  4. Apply the changes.
  5. Restart the container if necessary.

12. Verify Normal Operation

After restarting with a valid lineup, the logs should show the lineup being added and the initial XMLTV synchronization starting.

Monitor the logs with:

docker logs -f schedules-direct-xmltv

The resulting guide will be available at:

http://YOUR-SERVER-IP:51969/tvxml.xml

You can verify the XMLTV endpoint with:

curl -I http://YOUR-SERVER-IP:51969/tvxml.xml

A successful response should resemble:

HTTP/1.1 200 OK
Content-Type: text/xml

You can also inspect the beginning of the generated XMLTV file:

curl -s http://YOUR-SERVER-IP:51969/tvxml.xml | head -20

Guide Days

SD_FETCH_DAYS=2

Controls how many days of guide data are downloaded during each synchronization.

For example:

SD_FETCH_DAYS=7

downloads seven days of guide data.

Timezone

TZ=America/New_York

The container performs its scheduled guide refresh at midnight according to the configured timezone.

Examples:

America/New_York
America/Chicago
America/Denver
America/Los_Angeles

HTTP Port

XMLTV_PORT=51969

This controls the host port used to access the XMLTV file.

The container itself serves HTTP through nginx on port 80.

Accessing XMLTV

With the default configuration, the generated guide is available at:

http://YOUR-SERVER-IP:51969/tvxml.xml

For example:

http://192.168.1.100:51969/tvxml.xml

Use this URL as the XMLTV source in Threadfin, Jellyfin, Plex, Emby, TVHeadend, or another compatible application.

How It Works

When the container starts, it checks whether SD_LINEUPS has been configured.

Setup Mode

If SD_LINEUPS is blank:

  1. Runtime configuration is read from environment variables.
  2. The container enters setup mode.
  3. A base tv_grab_zz_sdjson configuration file is generated.
  4. Initial XMLTV synchronization is skipped.
  5. Scheduled synchronization through cron is disabled.
  6. nginx starts and keeps the container running.
  7. The included tv_grab_zz_sdjson configuration wizard can be used to discover or add a Schedules Direct lineup.

Setup mode allows a new user to install and start the container before knowing their Schedules Direct lineup ID.

Normal Mode

If SD_LINEUPS contains one or more lineup IDs:

  1. Runtime configuration is read from environment variables.
  2. A tv_grab_zz_sdjson configuration file is generated.
  3. The configured Schedules Direct lineups are added.
  4. Any stale Schedules Direct cache is removed.
  5. An initial XMLTV synchronization is performed.
  6. Cron is started for scheduled updates.
  7. nginx starts and serves the generated XMLTV data.

The initial synchronization and scheduled synchronization both use:

tv_grab_zz_sdjson

The generated XMLTV file is stored at:

/var/www/html/tvxml.xml

Scheduled Updates

When a lineup is configured, the container automatically refreshes the guide every day at midnight:

00:00

The configured TZ environment variable determines which timezone is used for the scheduled refresh.

Cron is disabled while the container is running in setup mode with an empty SD_LINEUPS.

Container logs show synchronization activity.

View logs with:

docker logs -f schedules-direct-xmltv

Typical output resembles:

[SYNC] Starting Schedules Direct data fetch...
[SYNC] Fetching 2 day(s) of guide data...
[SYNC] Completed Schedules Direct data fetch.
[SYNC] XMLTV output: /var/www/html/tvxml.xml

Persistent Data

The Docker Compose configuration uses the named volume:

xmltv_data

mounted at:

/var/www/html

This stores the generated XMLTV data and Schedules Direct configuration outside the container's writable layer.

The primary generated file is:

/var/www/html/tvxml.xml

Manual Docker Example

The container can also be run without Docker Compose.

If you already know your lineup ID:

docker run -d \
  --name schedules-direct-xmltv \
  -e SD_USERNAME="your_username" \
  -e SD_PASSWORD="your_password" \
  -e SD_LINEUPS="USA-OTA-10001" \
  -e SD_FETCH_DAYS="2" \
  -e TZ="America/New_York" \
  -p 51969:80 \
  -v xmltv_data:/var/www/html \
  --restart unless-stopped \
  heroeswearkapes/schedules-direct-xmltv:latest

Then access:

http://YOUR-SERVER-IP:51969/tvxml.xml

Manual Docker Setup Mode

If you do not know your lineup ID yet, omit SD_LINEUPS:

docker run -d \
  --name schedules-direct-xmltv \
  -e SD_USERNAME="your_username" \
  -e SD_PASSWORD="your_password" \
  -e SD_FETCH_DAYS="2" \
  -e TZ="America/New_York" \
  -p 51969:80 \
  -v xmltv_data:/var/www/html \
  --restart unless-stopped \
  heroeswearkapes/schedules-direct-xmltv:latest

Then run the configuration wizard:

docker exec -it schedules-direct-xmltv \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

After discovering your lineup ID, recreate the container with SD_LINEUPS configured.

Unraid

Schedules Direct XMLTV is available through Unraid Community Applications.

Search Community Applications for:

Schedules Direct XMLTV

During initial installation:

  • Enter your Schedules Direct username.
  • Enter your Schedules Direct password.
  • Leave Schedules Direct Lineups blank if you do not know your lineup ID yet.
  • Configure the desired guide days and timezone.
  • Configure the persistent XMLTV data path.

The container will start in setup mode when the lineup field is blank.

Open an Unraid terminal and run:

docker exec -it Schedules-Direct-XMLTV \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

Follow the lineup discovery procedure documented above.

Once you have the lineup ID:

  1. Edit the Schedules Direct XMLTV container.
  2. Enter the ID into Schedules Direct Lineups.
  3. Apply the changes.
  4. The container will restart and perform its initial guide synchronization.

Multi-Architecture Support

Published Docker images support:

linux/amd64
linux/arm64

This allows the same image to run on standard x86-64 Docker hosts as well as ARM64 systems such as compatible Raspberry Pi devices.

Updating

Docker Compose

docker compose pull
docker compose up -d

Docker CLI

docker pull heroeswearkapes/schedules-direct-xmltv:latest

Then recreate the container using the same environment variables, port mapping, and persistent volume.

Unraid

Updates can be installed through the normal Unraid Docker update process.

Persistent XMLTV data remains stored outside the container.

Troubleshooting

Container exits immediately

Check the logs:

docker logs schedules-direct-xmltv

The container requires both:

SD_USERNAME
SD_PASSWORD

If either is missing, startup will fail.

SD_LINEUPS is optional.

Leaving SD_LINEUPS blank does not cause the container to exit. The container starts in setup mode instead.

Container starts in setup mode

If the logs show:

[INFO] No Schedules Direct lineup configured.
[INFO] Starting in setup mode.

then SD_LINEUPS is blank.

This is expected for a first-time installation.

Run the configuration wizard:

docker exec -it schedules-direct-xmltv \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

For Unraid:

docker exec -it Schedules-Direct-XMLTV \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

After discovering your lineup ID, add it to SD_LINEUPS and recreate or restart the container.

Configuration wizard appears stuck at the cache prompt

The first wizard prompt looks like:

Cache file for lineups, schedules and programs.
Cache file: [/root/.xmltv/tv_grab_zz_sdjson.cache]

The wizard is waiting for input.

Press Enter to accept the default cache file and continue.

No lineup is shown on the Schedules Direct website

The newer Schedules Direct SD-JSON service manages lineups through applications using the API.

Use the included configuration wizard to query available lineups.

When prompted:

Edit account lineups: [continue,add,delete (default=continue)]

enter:

add

Then enter your country code and ZIP/postal code.

The wizard will query Schedules Direct and display the available lineups for your location.

XMLTV file is unavailable

Verify the container is running:

docker ps

Then check:

docker logs schedules-direct-xmltv

If the container is in setup mode, a valid guide will not be generated until SD_LINEUPS is configured.

Once a lineup is configured, allow the initial Schedules Direct synchronization to complete before accessing:

http://YOUR-SERVER-IP:51969/tvxml.xml

Verify the XMLTV endpoint

Run:

curl -I http://YOUR-SERVER-IP:51969/tvxml.xml

A working endpoint should return:

HTTP/1.1 200 OK
Content-Type: text/xml

You can also inspect the generated XML:

curl -s http://YOUR-SERVER-IP:51969/tvxml.xml | head -20

Incorrect or missing channels

Verify that SD_LINEUPS contains valid lineup IDs associated with your Schedules Direct account.

For example:

SD_LINEUPS=USA-OTA-10001

Multiple lineups must be separated by commas:

SD_LINEUPS=USA-OTA-10001,USA-YOUTUBE-X

You can use the configuration wizard to review the lineups currently enabled for your account.

Invalid lineup ID

If the container attempts synchronization and reports that the configured lineup is unavailable or invalid, verify the lineup through:

docker exec -it schedules-direct-xmltv \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

For Unraid:

docker exec -it Schedules-Direct-XMLTV \
  tv_grab_zz_sdjson \
  --configure \
  --config-file /tmp/sdjson-setup.conf

Then update SD_LINEUPS with the correct lineup ID.

Scheduled updates are not running

Scheduled updates are disabled while the container is in setup mode.

Verify that SD_LINEUPS is configured.

Then check the logs:

docker logs schedules-direct-xmltv

A normal startup with a valid lineup should include:

[INFO] Starting cron...

If cron does not start after a lineup is configured, recreate the container and check the startup logs for errors.

Change the number of guide days

Set:

SD_FETCH_DAYS=7

and recreate the container:

docker compose up -d

For Unraid, edit Guide Days, apply the changes, and restart the container.

Guide data appears stale

Check when the XMLTV file was last modified:

docker exec schedules-direct-xmltv \
  ls -lh /var/www/html/tvxml.xml

Then inspect recent synchronization logs:

docker logs schedules-direct-xmltv

The container normally refreshes the guide once per day at midnight according to the configured TZ.

Timezone or refresh time is incorrect

Verify:

TZ=America/New_York

or your preferred IANA timezone.

Examples:

America/New_York
America/Chicago
America/Denver
America/Los_Angeles

After changing the timezone, recreate or restart the container.

Port 51969 is already in use

Change:

XMLTV_PORT=51969

to another unused host port.

For example:

XMLTV_PORT=51970

The XMLTV URL would then become:

http://YOUR-SERVER-IP:51970/tvxml.xml

View container logs

Docker Compose:

docker compose logs -f

Docker CLI:

docker logs -f schedules-direct-xmltv

Unraid:

docker logs -f Schedules-Direct-XMLTV

Security

Schedules Direct credentials are runtime configuration.

Do not commit your .env file to Git.

The included .gitignore excludes:

.env
build.env

The .env.example file contains placeholders only and is safe to commit.

For Unraid, the Schedules Direct password field is masked in the Community Applications template.

Source

Project source:

https://github.com/heroeswearkapes/schedules-direct-xmltv

Docker Hub:

https://hub.docker.com/r/heroeswearkapes/schedules-direct-xmltv

Inspiration and Acknowledgements

This project was inspired by the original schedules-direct-update-and-serve project created by John Corser and its contributors.

Schedules Direct XMLTV is a separate implementation created to provide a maintained, multi-architecture Docker solution with simplified configuration, Docker Compose support, and Unraid integration.

This project uses tv_grab_zz_sdjson from the XMLTV utilities to retrieve guide data from Schedules Direct.

Community feedback and issue reports help improve the setup experience and documentation for new users.

Disclaimer

This is an independent community project.

It is not affiliated with or endorsed by Schedules Direct, XMLTV, Threadfin, Jellyfin, Plex, Emby, TVHeadend, Docker, or Unraid.

License

This project is licensed under the MIT License.

See the LICENSE file for the full license text.

Requirements


A valid Schedules Direct subscription is required.

If you already know your Schedules Direct lineup ID, enter it in the Schedules Direct Lineups field during installation.

If you do not know your lineup ID, leave Schedules Direct Lineups blank. The container will start in setup mode.

After the container starts, open either the Unraid Terminal or the container Console and run:

tv_grab_zz_sdjson --configure --config-file /tmp/sdjson-setup.conf

If using the Unraid Terminal instead of the container Console, run:

docker exec -it Schedules-Direct-XMLTV tv_grab_zz_sdjson --configure --config-file /tmp/sdjson-setup.conf

The configuration wizard will allow you to search for and add a Schedules Direct lineup using your country and ZIP/postal code.

After discovering your lineup ID, edit the container, enter the lineup ID in Schedules Direct Lineups, apply the changes, and restart the container.

The generated XMLTV guide will then be available at:

http://YOUR-UNRAID-IP:51969/tvxml.xml

Download Statistics

641
Total Downloads

Related apps

Details

Repository
heroeswearkapes/schedules-direct-xmltv:latest
Last Updated2026-08-30
First Seen2026-08-18

Runtime arguments

Network
bridge
Shell
bash
Privileged
false

Template configuration

XMLTV HTTP PortPorttcp

Host port used to serve the generated tvxml.xml file.

Target
80
Default
51969
Value
51969
Schedules Direct UsernameVariable

Your Schedules Direct account username.

Target
SD_USERNAME
Schedules Direct PasswordVariable

Your Schedules Direct account password.

Target
SD_PASSWORD
Schedules Direct LineupsVariable

Optional comma-separated Schedules Direct lineup IDs. Leave blank during initial setup if you do not know your lineup ID yet. After the container starts, use the SD-JSON configuration wizard to discover or add a lineup. Example: USA-OTA-10001

Target
SD_LINEUPS
Guide DaysVariable

Number of days of guide data to download during each synchronization.

Target
SD_FETCH_DAYS
Default
2
Value
2
TimezoneVariable

Timezone used by the container and the scheduled midnight guide refresh.

Target
TZ
Default
America/New_York
Value
America/New_York
XMLTV DataPathrw

Persistent storage for generated XMLTV data and Schedules Direct configuration.

Target
/var/www/html
Default
/mnt/user/appdata/schedules-direct-xmltv
Value
/mnt/user/appdata/schedules-direct-xmltv