npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@iptv/xmltv

v1.0.1

Published

An extremely fast XMLTV parser and generator for Node and the browser.

Downloads

1,681

Readme

@iptv/xmltv

An extremely fast XMLTV parser and generator for Node and the browser. Lightweight, dependency-free, and easy to use.


npm GitHub Workflow Status Coverage GitHub


The average XMLTV file is pretty large, smaller ones around 20MB and larger ones exceeding hundreds of megabytes. The purpose of this library is to facilitate rapid parsing and creation of these files.


✨ Features

  • Extremely fast XMLTV parser and generator
  • Lightweight (3.74 kB gzipped)
  • No dependencies
  • ESM and CommonJS support
  • Supports Node and the browser
  • Types that define an Xmltv interface, which implements the XMLTV DTD as closely as possible
  • Supports all XMLTV elements and attributes
  • Did I mention it's fast?

📥 Installation

To install this library, use the following command:

# pnpm
pnpm add @iptv/xmltv

# npm
npm install @iptv/xmltv

# yarn
yarn add @iptv/xmltv

🔧 Usage

To use this library in your project, first import the functions you need:

import { parseXmltv, writeXmltv } from '@iptv/xmltv';

Then, you can parse an XMLTV file and receive back an Xmltv object:

Examples will be based on this XMLTV file, it can be found in the tests/fixtures directory.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">

<tv date="20220401000000 +0000" source-info-name="example" source-info-url="example.com" source-data-url="example.com/a" generator-info-name="Example Generator"
  generator-info-url="example generator url">
  <channel id="channel_one">
    <display-name lang="en">Channel One</display-name>
    <icon src="https://example.com/channel_one_icon.jpg" width="100" height="100" />
    <url system="example">https://example.com/channel_one</url>
    <url system="other_system">https://example.com/channel_one_alternate</url>
  </channel>
  <channel id="channel_two">
    <display-name>Channel Two: Minimum valid channel</display-name>
  </channel>
  <programme start="20220331180000 +0000" stop="20220331190000 +0000" channel="channel_one"
    pdc-start="20220331180000 +0000" vps-start="20220331180000 +0000" showview="12345"
    videoplus="67890" clumpidx="0/1">
    <title lang="en">Programme One</title>
    <sub-title lang="en">Pilot</sub-title>
    <desc lang="en">This programme entry showcases all possible features of the DTD</desc>
    <credits>
      <director>Samuel Jones</director>
      <actor role="Walter Johnson">David Thompson</actor>
      <actor role="Karl James" guest="yes"> Ryan Lee <image type="person">https://www.example.com/xxx.jpg</image>
        <url system="moviedb">https://www.example.com/person/204</url>
      </actor>
      <writer>Samuel Jones</writer>
      <adapter>William Brown</adapter>
      <producer>Emily Davis</producer>
      <composer>Max Wright</composer>
      <editor>Nora Peterson</editor>
      <presenter>Amanda Johnson</presenter>
      <commentator>James Wilson</commentator>
      <guest>Lucas Martin</guest>
      <guest>Emily Parker</guest>
      <guest>Oliver Nelson</guest>
    </credits>
    <date>20220401000000 +0000</date>
    <category lang="en">Crime</category>
    <category lang="en">Drama</category>
    <keyword lang="en">methamphetamine</keyword>
    <keyword lang="en">cancer</keyword>
    <language>English</language>
    <orig-language lang="en">French</orig-language>
    <length units="minutes">60</length>
    <icon src="https://example.com/programme_one_icon.jpg" width="100" height="100" />
    <url system="tvdb">https://example.com/programme_one</url>
    <url> https://example.com/programme_one_2</url>
    <country>US</country>
    <episode-num system="onscreen">S01E01</episode-num>
    <episode-num system="xmltv_ns">1.1.</episode-num>
    <video>
      <present>yes</present>
      <colour>no</colour>
      <aspect>16:9</aspect>
      <quality>HDTV</quality>
    </video>
    <audio>
      <present>yes</present>
      <stereo>Dolby Digital</stereo>
    </audio>
    <previously-shown start="20220331180000 +0000" channel="channel_two" />
    <premiere>First time on British TV</premiere>
    <last-chance lang="en">Last time on this channel</last-chance>
    <new />
    <subtitles type="teletext">
      <language>English</language>
    </subtitles>
    <subtitles type="onscreen">
      <language lang="en">Spanish</language>
    </subtitles>
    <rating system="BBFC">
      <value>15</value>
      <icon src="15_symbol.png" />
    </rating>
    <star-rating system="TV Guide">
      <value> 4/5</value>
      <icon src="stars.png" />
    </star-rating>
    <review type="text" source="Rotten Tomatoes" reviewer="Joe Bloggs" lang="en">This is a fantastic show!</review>
    <review type="url" source="Rotten Tomatoes" reviewer="Joe Bloggs" lang="en">https://example.com/programme_one_review</review>
    <image type="poster" size="1" orient="P" system="tvdb">https://tvdb.com/programme_one_poster_1.jpg</image>
    <image type="backdrop" size="3" orient="L" system="tvdb"> https://tvdb.com/programme_one_backdrop_3.jpg</image>
  </programme>
  <programme start="20220331180000 +0000"
    channel="channel_one">
    <title>Programme Two: The minimum valid programme</title>
  </programme>
</tv>
const xml = `...`; // XMLTV file contents
const xmltv: Xmltv = parseXmltv(xml);
const programmes: XmltvProgramme[] = xmltv.programmes;
const channels: XmltvChannel[] = xmltv.channels;
{
  channels: [
    {
      displayName: [
        {
          _value: "Channel One",
          lang: "en",
        },
      ],
      icon: [
        {
          height: 100,
          src: "https://example.com/channel_one_icon.jpg",
          width: 100,
        },
      ],
      id: "channel_one",
      url: [
        {
          _value: "https://example.com/channel_one",
          system: "example",
        },
        {
          _value: "https://example.com/channel_one_alternate",
          system: "other_system",
        },
      ],
    },
    {
      displayName: [
        {
          _value: "Channel Two: Minimum valid channel",
        },
      ],
      id: "channel_two",
    },
  ],
  date: new Date("2022-04-01T00:00:00.000Z"),
  generatorInfoName: "Example Generator",
  generatorInfoUrl: "example generator url",
  programmes: [
    {
      audio: {
        present: true,
        stereo: "Dolby Digital",
      },
      category: [
        {
          _value: "Crime",
          lang: "en",
        },
        {
          _value: "Drama",
          lang: "en",
        },
      ],
      channel: "channel_one",
      clumpidx: "0/1",
      country: {
        _value: "US",
      },
      credits: {
        actor: [
          {
            _value: "David Thompson",
            role: "Walter Johnson",
          },
          {
            _value: "Ryan Lee",
            guest: true,
            image: [
              {
                _value: "https://www.example.com/xxx.jpg",
                type: "person",
              },
            ],
            role: "Karl James",
            url: [
              {
                _value: "https://www.example.com/person/204",
                system: "moviedb",
              },
            ],
          },
        ],
        adapter: [
          {
            _value: "William Brown",
          },
        ],
        commentator: [
          {
            _value: "James Wilson",
          },
        ],
        composer: [
          {
            _value: "Max Wright",
          },
        ],
        director: [
          {
            _value: "Samuel Jones",
          },
        ],
        editor: [
          {
            _value: "Nora Peterson",
          },
        ],
        guest: [
          {
            _value: "Lucas Martin",
          },
          {
            _value: "Emily Parker",
          },
          {
            _value: "Oliver Nelson",
          },
        ],
        presenter: [
          {
            _value: "Amanda Johnson",
          },
        ],
        producer: [
          {
            _value: "Emily Davis",
          },
        ],
        writer: [
          {
            _value: "Samuel Jones",
          },
        ],
      },
      date: new Date("2022-04-01T00:00:00.000Z"),
      desc: [
        {
          _value:
            "This programme entry showcases all possible features of the DTD",
          lang: "en",
        },
      ],
      episodeNum: [
        {
          _value: "S01E01",
          system: "onscreen",
        },
        {
          _value: "1.1.",
          system: "xmltv_ns",
        },
      ],
      icon: [
        {
          height: 100,
          src: "https://example.com/programme_one_icon.jpg",
          width: 100,
        },
      ],
      image: [
        {
          _value: "https://tvdb.com/programme_one_poster_1.jpg",
          orient: "P",
          size: 1,
          system: "tvdb",
          type: "poster",
        },
        {
          _value: "https://tvdb.com/programme_one_backdrop_3.jpg",
          orient: "L",
          size: 3,
          system: "tvdb",
          type: "backdrop",
        },
      ],
      keyword: [
        {
          _value: "methamphetamine",
          lang: "en",
        },
        {
          _value: "cancer",
          lang: "en",
        },
      ],
      language: {
        _value: "English",
      },
      lastChance: {
        _value: "Last time on this channel",
        lang: "en",
      },
      length: {
        _value: 60,
        units: "minutes",
      },
      new: true,
      origLanguage: {
        _value: "French",
        lang: "en",
      },
      pdcStart: new Date("2022-03-31T18:00:00.000Z"),
      premiere: {
        _value: "First time on British TV",
      },
      previouslyShown: {
        channel: "channel_two",
        start: new Date("2022-03-31T18:00:00.000Z"),
      },
      rating: [
        {
          icon: [
            {
              src: "15_symbol.png",
            },
          ],
          system: "BBFC",
          value: "15",
        },
      ],
      review: [
        {
          _value: "This is a fantastic show!",
          lang: "en",
          reviewer: "Joe Bloggs",
          source: "Rotten Tomatoes",
          type: "text",
        },
        {
          _value: "https://example.com/programme_one_review",
          lang: "en",
          reviewer: "Joe Bloggs",
          source: "Rotten Tomatoes",
          type: "url",
        },
      ],
      showview: "12345",
      starRating: [
        {
          icon: [
            {
              src: "stars.png",
            },
          ],
          system: "TV Guide",
          value: "4/5",
        },
      ],
      start: new Date("2022-03-31T18:00:00.000Z"),
      stop: new Date("2022-03-31T19:00:00.000Z"),
      subTitle: [
        {
          _value: "Pilot",
          lang: "en",
        },
      ],
      subtitles: [
        {
          language: {
            _value: "English",
          },
          type: "teletext",
        },
        {
          language: {
            _value: "Spanish",
            lang: "en",
          },
          type: "onscreen",
        },
      ],
      title: [
        {
          _value: "Programme One",
          lang: "en",
        },
      ],
      url: [
        {
          _value: "https://example.com/programme_one",
          system: "tvdb",
        },
        {
          _value: "https://example.com/programme_one_2",
        },
      ],
      video: {
        aspect: "16:9",
        colour: false,
        present: true,
        quality: "HDTV",
      },
      videoplus: "67890",
      vpsStart: new Date("2022-03-31T18:00:00.000Z"),
    },
    {
      channel: "channel_one",
      start: new Date("2022-03-31T18:00:00.000Z"),
      title: [
        {
          _value: "Programme Two: The minimum valid programme",
        },
      ],
    },
  ],
  sourceDataUrl: "example.com/a",
  sourceInfoName: "example",
  sourceInfoUrl: "example.com",
};

You can also generate an XMLTV file from an Xmltv tree:

const xml = writeXmltv(xmltvObject);
console.log(xml); // <tv>...</tv>

Or from a XMLTV DOM tree:

const xml = writeXmltv(xmltvDom, { fromDom: true });
console.log(xml); // <tv>...</tv>

If you want to go even faster you can parse the file into a DOM tree and then traverse it yourself:

const xml = '...'; // XMLTV file contents
const parsed = parseXmltv(xml, { asDom: true });
// or import { parser } from '@iptv/xmltv';
// const parsed = parser(xml);

// `parsed` is now a list of XmltvNode objects
// which can be traversed using the `children` property
// and attributes can be accessed using the `attributes` property
// (see the XmltvNode interface for more details)

// this is not the most efficient way to do this, but it's a good example
const programmes = parsed
  .find((node) => {
    // find the <tv> tag
    return node.tagName === 'tv';
  })
  .children.filter((node) => {
    // filter it's children for <programme> tags
    return node.tagName === 'programme';
  })
  .map((programme) => {
    // return a Programme object for each <programme> tag
    return {
      title: programme.children.find((t) => t.tagName === 'title').children[0],
      start: new Date(programme.attributes.start),
      stop: new Date(programme.attributes.stop),
      channel: programme.attributes.channel,
    };
  });

⚡ Performance

This library has been optimized for parsing and generating XMLTV files quickly and efficiently. In my benchmarks, it performs better than other popular XMLTV libraries, including epg-parser and xmltv. It also beats fast-xml-parser.

The speed of this library is down to the implementation of the XML DOM tree parser tXml. To learn more about the optimisations made by tXml please read this blog post by @TobiasNickel.

Benchmarks

Parsing XMLTV file (c1-p1.xml)

Writing XMLTV file (c1-p1.xml)

Time spent parsing different XMLTV files


🎯 Future Goals

Worker Support

Even though it's fast and it won't block for long, this will block your main thread whilst it runs. I'd like to add support for running the parser in a worker so it doesn't block at all.

Streaming Support

My initial intent writing this library was to build a streaming parser, however I found the approach of tXml to be much faster than other methods I tried. There are some issues upstream I'd like to help fix before I can add streaming support but it is something I'd like to do.

CLI Module

A command line program that can be piped around to convert files from one format to another.

🚫 Non-Goals

Generic XML Parsing

This library is designed to parse and generate XMLTV files only. It is not designed to be a generic XML parser or generator. If you need to parse generic XML files, you should use the excellent tXml library instead.

Altering the Shape of the Data

The shape of the Xmltv type is designed to match the XMLTV DTD as closely as possible. If you need a different object you can traverse the DOM tree yourself and convert it to your desired shape.


🤝 Contributing

Contributions are welcome! Even better if they align with the future goals.

You'll need to be able to run the tests and benchmarks. To do so, you will need to run the ./create-fixtures.sh script in the tests/fixtures directory to generate the necessary fixture files.

To be accepted your PR must pass all tests and not negatively impact the benchmarks. Some commands to help you:

  • pnpm run test - Run the vitest suite
  • pnpm run benny - Run additional benchmarks
  • pnpm run benchmark - Run the benchmarks with vitest
  • pnpm run nanobench - Run additional benchmarks

This project uses Changesets to manage releases. For you, this just means your PR must come with an appropriate changeset file. If you're not sure how to do this, just ask and I'll be happy to help, or read the changesets documentation on adding a changeset.

📄 License & Credit

This library is licensed under the MIT License and is free to use in both open source and commercial projects.

The parser is based on the tXml library by @TobiasNickel.