This project aims to create an open-source tool that converts VAST XML files into HLS interstitial AssetLists and DASH Alternative MPD, supporting Server-Guided Ad Insertion (SGAI).
-
Start the project
There are two main ways to run the project:
-
Using Docker Compose (Recommended for most users):
docker compose up
This command will build the Docker image (if not already built) and start the service. The service will be available at
http://localhost:3000. -
Using Node.js directly:
npm install npm run dev
This will start the development server using
nodemon, which automatically restarts the application when file changes are detected.
-
-
Access the examples
Once the server is running, open a browser and navigate to
http://localhost:3000to see the main page with links to various examples.Note on Environment Variables: The project uses environment variables for configuration. A template file
.env.exampleis provided. You can copy this to a.envfile and customize the values as needed. These variables control aspects like the port, API behavior, and security settings. See the "Service Configuration" section for more details.
The service can be configured using environment variables. Create a .env file in the root of the project (you can copy .env.example as a starting point) and set the following variables as needed:
PORT: The port on which the server will listen. Defaults to3000.PINO_LOG_LEVEL: Sets the logging level for the application. Common values aredebug,info,warn,error. Defaults todebug.API_DISABLE_SIGN: If set totrue, disables the/api/signendpoint, preventing the generation of new JWTs. Defaults tofalse.JWT_SECRET_KEY: A secret key used to sign and verify JWTs. You should generate a strong, unique key for production environments. You can generate one using:node -e "console.log(require('crypto').randomBytes(32).toString('hex'))".JWT_BYPASS_VALIDATION: If set totrue, JWT validation will be bypassed. This is not recommended for production. Defaults tofalse.JWT_EXPIRES_IN: Defines the expiration time for JWTs (e.g.,1h,7d,10y). Defaults to10y.VAST_WHITELIST: A comma-separated list of domains that are allowed to be used in thevasturlparameter if JWT is not used. Example:www.example.com,adserver.anotherdomain.net.ORIGIN_WHITELIST: A comma-separated list of origins (e.g.,http://localhost:8080,https://myplayer.com) that are allowed to make requests to the API. If empty, all origins are allowed (CORS*).VAST_MAPPING_JSON: A JSON string that maps short IDs to full VAST URLs. This is used by thevastidparameter. Example:{"1": "http://example.com/vast1.xml", "promo": "http://anotherexample.com/promo.xml"}. The keys will be used as values for thevastidquery parameter.
To apply these settings, ensure the .env file is present in the project root before starting the application. If using Docker, the variables can also be set in the docker-compose.yml file or passed directly during container runtime.
The service exposes the following API endpoints:
Converts a VAST XML into an HLS AssetList JSON format, suitable for Server-Guided Ad Insertion (SGAI).
- Purpose: To provide a list of ad assets that can be directly consumed by HLS players supporting interstitial events.
- Request Parameters:
vasturl=<URL>: The direct URL to a VAST XML file. This parameter is subject to theVAST_WHITELISTif nojwtis provided.vastid=<ID>: An ID that maps to a VAST URL pre-configured in theVAST_MAPPING_JSONenvironment variable.jwt=<TOKEN>: A JSON Web Token previously generated by the/api/signendpoint. The VAST URL is embedded within this token, bypassing the whitelist.- Additional query parameters: Any other query parameters sent to this endpoint will be appended to the VAST URL before fetching it. This allows for dynamic parameter passing to the VAST server (e.g., for cache busting or user tracking).
- Response:
200 OK: Returns a JSON object representing the HLS AssetList.{ "ASSETS": [ { "URI": "URL_to_ad_creative.mp4", "DURATION": 15.0, "X-AD-CREATIVE-SIGNALING": { /* ... Ad signaling data ... */ }, "X-VAST2SGAI-VIDEOCLICKS": { /* ... Click tracking data ... */ } } // ... more assets if present in VAST ] }400 Bad Request: If required parameters are missing, the VAST URL is invalid, or VAST parsing fails.401 Unauthorized: Ifjwtis invalid or other security checks fail.
Converts a VAST XML into an MPEG-DASH MPD of type="list". This MPD will contain a sequence of Periods, each importing an ad creative's MPD.
- Purpose: To provide a structured list of ad content manifest URLs, allowing a DASH player to play a sequence of ads from their individual MPDs. This is particularly useful for scenarios where ads are served as separate, complete MPDs.
- Request Parameters:
vasturl=<URL>: The direct URL to a VAST XML file (subject toVAST_WHITELISTif nojwt).vastid=<ID>: An ID fromVAST_MAPPING_JSON.jwt=<TOKEN>: A JWT containing the VAST URL.- Additional query parameters: Appended to the VAST URL before fetching it.
- Response:
200 OK: Returns an XML document withContent-Type: application/dash+xml. The MPD will be oftype="list"and conform to theurn:mpeg:dash:profile:list:2024profile.<?xml version="1.0" encoding="UTF-8"?> <MPD xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:mpeg:dash:schema:mpd:2011" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" type="list" minBufferTime="PT1S" profiles="urn:mpeg:dash:profile:list:2024" publishTime="YYYY-MM-DDTHH:MM:SS.mmmZ"> <Period id="1" duration="PT[Ad1Duration]S"> <ImportedMPD uri="[URL_to_Ad1_MPD]" earliestResolutionTimeOffset="0"/> </Period> <Period id="2" duration="PT[Ad2Duration]S"> <ImportedMPD uri="[URL_to_Ad2_MPD]" earliestResolutionTimeOffset="[Time_to_load]"/> </Period> <!-- ... more Periods for additional ads ... --> </MPD>
publishTime: The time when this list MPD was generated.- Each
<Period>corresponds to an ad from the VAST. duration: The duration of the ad creative (e.g.,PT15Sfor 15 seconds).<ImportedMPD uri="..." />: Specifies the URL to the MPD of the individual ad creative.earliestResolutionTimeOffset: Indicates the earliest time, relative to the start of the Period, at which the player may attempt to resolve theImportedMPDURI. It's0for the first Period and typically a value like10(seconds) for subsequent Periods, allowing for staggered resolution.
400 Bad Request: For invalid parameters or VAST processing issues.401 Unauthorized: For security violations (e.g., invalid JWT).
Generates a JSON Web Token (JWT) for a given VAST URL. This token can then be used with the jwt parameter in the /api/asset-list and /api/list-mpd endpoints.
- Purpose: To securely authorize requests for specific VAST URLs without needing to whitelist them, and to prevent tampering with the VAST URL.
- Request:
- GET: The VAST URL must be provided as a query parameter:
/api/sign?url=<VAST_URL_to_sign>. - POST: The VAST URL must be provided in the JSON body:
{ "url": "<VAST_URL_to_sign>" }.
- GET: The VAST URL must be provided as a query parameter:
- Response:
200 OK: Returns a plain text string containing the generated JWT.400 Bad Request: If theurlparameter/body field is missing.401 Unauthorized: If theAPI_DISABLE_SIGNenvironment variable is set totrue.
- Note: The security of this endpoint relies on the
JWT_SECRET_KEY. Ensure this key is kept confidential.
This section provides guidance on deploying the VAST-2-SGAI service.
The most straightforward way to deploy the application is by using Docker. The project includes a Dockerfile for building the image and a docker-compose.yml for orchestration, which is suitable for both development and production-like environments.
-
Build the Docker Image: If you need to build the image manually (e.g., for a custom registry or environment), you can use:
docker build -t vast-2-sgai . -
Run with Docker Compose: For a typical deployment, you can adapt the existing
docker-compose.ymlor create a production-specific one.- Ensure you have a
.envfile in the project root with your production configurations (see "Service Configuration" section). Docker Compose will automatically pick up this file. - Start the service:
The
docker compose -f docker-compose.yml up -d
-dflag runs the container in detached mode.
- Ensure you have a
-
Run directly with
docker run: Alternatively, you can run the built image directly:docker run -d -p 3000:3000 --env-file ./.env vast-2-sgai
Make sure your
.envfile is correctly populated and accessible. You might need to adjust the port mapping (-p) as per your requirements.
While Docker is recommended for ease of deployment and consistency, you can also run the application directly using Node.js in a production environment.
-
Prerequisites:
- Node.js (version specified in
Dockerfileor newer LTS) - npm
- Node.js (version specified in
-
Setup:
- Clone the repository to your server.
- Create a
.envfile with your production configurations. - Install dependencies:
The
npm install --omit=dev
--omit=devflag (orNODE_ENV=production npm installfor older npm versions) installs only production dependencies.
-
Run the Application: Start the application using a process manager like PM2, which provides features like automatic restarts, logging, and monitoring.
npm start
Or, if using PM2:
pm2 start src/server.js --name vast-2-sgai
For any serious production deployment, it's highly recommended to run the application behind a reverse proxy like Nginx or Apache.
-
Benefits:
- SSL/TLS Termination: Handle HTTPS traffic and manage SSL certificates.
- Load Balancing: If you plan to run multiple instances of the application.
- Caching: Serve static assets or cache API responses.
- Security: Additional layer of protection (e.g., rate limiting, IP blocking).
-
Example Nginx Configuration Snippet:
server { listen 80; server_name yourdomain.com; # Redirect HTTP to HTTPS location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; server_name yourdomain.com; ssl_certificate /etc/nginx/ssl/yourdomain.com.crt; ssl_certificate_key /etc/nginx/ssl/yourdomain.com.key; location / { proxy_pass http://localhost:3000; # Assuming VAST-2-SGAI runs on port 3000 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; 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; } }
Remember to replace
yourdomain.comand paths to SSL certificates.
The project includes several examples in the public/samples/ directory. When the server is running (e.g., via docker compose up or npm run dev), these can be accessed at http://localhost:3000/samples/.
Each example typically includes an index.html file that demonstrates a particular feature or use case.
asset-list-1: Access Example- Demonstrates a basic HLS stream with a single interstitial ad inserted at 5 seconds.
asset-list-2: Access Example- Shows an HLS stream with an Ad POD (multiple ads) inserted as an interstitial at 5 seconds.
dash-alt-mpd: Access Example- Illustrates MPEG-DASH playback using
dash.jswith ads signaled via an alternative MPD (/api/list-mpd). Includes CMCD v2 reporting.
- Illustrates MPEG-DASH playback using
sample-ad-click: Access Example- Focuses on VAST click tracking functionality within an HLS interstitial, using the
videoClicksPlugin.js.
- Focuses on VAST click tracking functionality within an HLS interstitial, using the
sample-ad-signaling: Access Example- Demonstrates VAST tracking events (e.g., impression, start, complete) being signaled from an HLS interstitial using
adCreativeSignalingPlugin.js.
- Demonstrates VAST tracking events (e.g., impression, start, complete) being signaled from an HLS interstitial using
sample-api-jwt: Access Example- Shows how to use the
/api/asset-listendpoint with a JWT to securely provide the VAST URL. Includes an example JWT and the corresponding VAST.
- Shows how to use the
sample-api-vastid: Access Example- Demonstrates using the
/api/asset-listendpoint with thevastidparameter, which maps to a pre-configured VAST URL in the server's environment variables.
- Demonstrates using the
sample-api-vastid-live: Access Example- Live HLS stream (Big Buck Bunny restreamed) demonstrating dynamic ad insertion via Wowza Streaming Engine API calls, using
vastid.
- Live HLS stream (Big Buck Bunny restreamed) demonstrating dynamic ad insertion via Wowza Streaming Engine API calls, using
sample-api-vastid-live2: Access Example- Similar to
sample-api-vastid-live, but the live source is a WebRTC stream published to Wowza.
- Similar to
sample-api-vastid-live3: Access Example- Live HLS stream from an RTSP camera via Wowza, with dynamic ad insertion using
vastid.
- Live HLS stream from an RTSP camera via Wowza, with dynamic ad insertion using
sample-api-vastid-live4: Access Example- Live HLS stream from an RTMP source (e.g., ffmpeg) via Wowza, with dynamic ad insertion using
vastid.
- Live HLS stream from an RTMP source (e.g., ffmpeg) via Wowza, with dynamic ad insertion using
sample-api-vasturl: Access Example- Shows the use of
/api/asset-listwith thevasturlparameter, directly providing the VAST XML URL.
- Shows the use of
sample-edit-vast: Access Example- An interactive demo allowing users to input their own VAST URL and parameters (duration, start date, etc.) to dynamically generate and play an HLS stream with interstitials. It displays the fetched VAST and the parsed AssetList.
sample-vast-1: Access Example- A basic example showing an HLS stream with an interstitial ad from a VAST XML, similar to
asset-list-1but structured as a general VAST sample.
- A basic example showing an HLS stream with an interstitial ad from a VAST XML, similar to
sample-vast-set/: This directory contains a set of VAST XML files (e.g.,vast_01_15s.xml,vast_02_30s.xml) that are used by other examples or can be used for testing. They do not have directindex.htmlplayers themselves but are referenced by other samples or API calls.
These examples are valuable for understanding the capabilities of VAST-2-SGAI and for testing different configurations.