{"id":20892679,"url":"https://github.com/ektotv/xmltv","last_synced_at":"2025-05-12T22:31:57.246Z","repository":{"id":152068733,"uuid":"624121061","full_name":"ektotv/xmltv","owner":"ektotv","description":"An extremely fast XMLTV parser and generator for Node and the browser.","archived":false,"fork":false,"pushed_at":"2023-11-27T14:55:10.000Z","size":661,"stargazers_count":19,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-11-06T09:18:57.058Z","etag":null,"topics":["epg","parser","xmltv"],"latest_commit_sha":null,"homepage":"https://npmjs.com/package/@iptv/xmltv","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ektotv.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-04-05T19:40:08.000Z","updated_at":"2024-09-10T06:05:15.000Z","dependencies_parsed_at":"2023-11-27T16:04:20.166Z","dependency_job_id":null,"html_url":"https://github.com/ektotv/xmltv","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ektotv%2Fxmltv","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ektotv%2Fxmltv/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ektotv%2Fxmltv/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ektotv%2Fxmltv/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ektotv","download_url":"https://codeload.github.com/ektotv/xmltv/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225156991,"owners_count":17429701,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["epg","parser","xmltv"],"created_at":"2024-11-18T10:13:36.096Z","updated_at":"2024-11-18T10:13:36.649Z","avatar_url":"https://github.com/ektotv.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"./logo-dark.svg\"\u003e\n    \u003cimg alt=\"XMLTV. TypeScript tools for working with EPG data.\" src=\"./logo.svg\"\u003e\n  \u003c/picture\u003e\n\n# @iptv/xmltv\n\nAn extremely fast XMLTV parser and generator for Node and the browser. \u003cbr\u003eLightweight, dependency-free, and easy to use.\n\n---\n\n[![npm](https://img.shields.io/npm/v/@iptv/xmltv?style=flat-square)](https://www.npmjs.com/package/@iptv/xmltv)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/ektotv/xmltv/ci.yml?branch=main\u0026style=flat-square)](https://github.com/ektotv/xmltv/actions/workflows/ci.yml)\n[![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/evoactivity/4b433bda8a479155a5a36b1a8341b97c/raw/iptv_xmltv_coverage.json\u0026style=flat-square)](https://github.com/ektotv/xmltv/tree/main/tests)\n[![GitHub](https://img.shields.io/github/license/ektotv/xmltv?style=flat-square)](LICENSE.md)\n\n\u003c/div\u003e\n\n---\n\nThe 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.\n\n---\n\n## ✨ Features\n\n- **Extremely** fast XMLTV parser and generator\n- Lightweight (3.74 kB gzipped)\n- No dependencies\n- ESM and CommonJS support\n- Supports Node and the browser\n- Types that define an Xmltv interface, which implements the [XMLTV DTD](https://github.com/XMLTV/xmltv/blob/master/xmltv.dtd) as closely as possible\n- Supports **all** XMLTV elements and attributes\n- Did I mention [it's fast](#-performance)?\n\n---\n\n## 📥 Installation\n\nTo install this library, use the following command:\n\n```bash\n# pnpm\npnpm add @iptv/xmltv\n\n# npm\nnpm install @iptv/xmltv\n\n# yarn\nyarn add @iptv/xmltv\n```\n\n---\n\n## 🔧 Usage\n\nTo use this library in your project, first import the functions you need:\n\n```typescript\nimport { parseXmltv, writeXmltv } from '@iptv/xmltv';\n```\n\nThen, you can parse an XMLTV file and receive back an `Xmltv` object:\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample XMLTV File\u003c/summary\u003e\n\nExamples will be based on this XMLTV file, it can be found in the [tests/fixtures](tests/fixtures) directory.\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003c!DOCTYPE tv SYSTEM \"xmltv.dtd\"\u003e\n\n\u003ctv date=\"20220401000000 +0000\" source-info-name=\"example\" source-info-url=\"example.com\" source-data-url=\"example.com/a\" generator-info-name=\"Example Generator\"\n  generator-info-url=\"example generator url\"\u003e\n  \u003cchannel id=\"channel_one\"\u003e\n    \u003cdisplay-name lang=\"en\"\u003eChannel One\u003c/display-name\u003e\n    \u003cicon src=\"https://example.com/channel_one_icon.jpg\" width=\"100\" height=\"100\" /\u003e\n    \u003curl system=\"example\"\u003ehttps://example.com/channel_one\u003c/url\u003e\n    \u003curl system=\"other_system\"\u003ehttps://example.com/channel_one_alternate\u003c/url\u003e\n  \u003c/channel\u003e\n  \u003cchannel id=\"channel_two\"\u003e\n    \u003cdisplay-name\u003eChannel Two: Minimum valid channel\u003c/display-name\u003e\n  \u003c/channel\u003e\n  \u003cprogramme start=\"20220331180000 +0000\" stop=\"20220331190000 +0000\" channel=\"channel_one\"\n    pdc-start=\"20220331180000 +0000\" vps-start=\"20220331180000 +0000\" showview=\"12345\"\n    videoplus=\"67890\" clumpidx=\"0/1\"\u003e\n    \u003ctitle lang=\"en\"\u003eProgramme One\u003c/title\u003e\n    \u003csub-title lang=\"en\"\u003ePilot\u003c/sub-title\u003e\n    \u003cdesc lang=\"en\"\u003eThis programme entry showcases all possible features of the DTD\u003c/desc\u003e\n    \u003ccredits\u003e\n      \u003cdirector\u003eSamuel Jones\u003c/director\u003e\n      \u003cactor role=\"Walter Johnson\"\u003eDavid Thompson\u003c/actor\u003e\n      \u003cactor role=\"Karl James\" guest=\"yes\"\u003e Ryan Lee \u003cimage type=\"person\"\u003ehttps://www.example.com/xxx.jpg\u003c/image\u003e\n        \u003curl system=\"moviedb\"\u003ehttps://www.example.com/person/204\u003c/url\u003e\n      \u003c/actor\u003e\n      \u003cwriter\u003eSamuel Jones\u003c/writer\u003e\n      \u003cadapter\u003eWilliam Brown\u003c/adapter\u003e\n      \u003cproducer\u003eEmily Davis\u003c/producer\u003e\n      \u003ccomposer\u003eMax Wright\u003c/composer\u003e\n      \u003ceditor\u003eNora Peterson\u003c/editor\u003e\n      \u003cpresenter\u003eAmanda Johnson\u003c/presenter\u003e\n      \u003ccommentator\u003eJames Wilson\u003c/commentator\u003e\n      \u003cguest\u003eLucas Martin\u003c/guest\u003e\n      \u003cguest\u003eEmily Parker\u003c/guest\u003e\n      \u003cguest\u003eOliver Nelson\u003c/guest\u003e\n    \u003c/credits\u003e\n    \u003cdate\u003e20220401000000 +0000\u003c/date\u003e\n    \u003ccategory lang=\"en\"\u003eCrime\u003c/category\u003e\n    \u003ccategory lang=\"en\"\u003eDrama\u003c/category\u003e\n    \u003ckeyword lang=\"en\"\u003emethamphetamine\u003c/keyword\u003e\n    \u003ckeyword lang=\"en\"\u003ecancer\u003c/keyword\u003e\n    \u003clanguage\u003eEnglish\u003c/language\u003e\n    \u003corig-language lang=\"en\"\u003eFrench\u003c/orig-language\u003e\n    \u003clength units=\"minutes\"\u003e60\u003c/length\u003e\n    \u003cicon src=\"https://example.com/programme_one_icon.jpg\" width=\"100\" height=\"100\" /\u003e\n    \u003curl system=\"tvdb\"\u003ehttps://example.com/programme_one\u003c/url\u003e\n    \u003curl\u003e https://example.com/programme_one_2\u003c/url\u003e\n    \u003ccountry\u003eUS\u003c/country\u003e\n    \u003cepisode-num system=\"onscreen\"\u003eS01E01\u003c/episode-num\u003e\n    \u003cepisode-num system=\"xmltv_ns\"\u003e1.1.\u003c/episode-num\u003e\n    \u003cvideo\u003e\n      \u003cpresent\u003eyes\u003c/present\u003e\n      \u003ccolour\u003eno\u003c/colour\u003e\n      \u003caspect\u003e16:9\u003c/aspect\u003e\n      \u003cquality\u003eHDTV\u003c/quality\u003e\n    \u003c/video\u003e\n    \u003caudio\u003e\n      \u003cpresent\u003eyes\u003c/present\u003e\n      \u003cstereo\u003eDolby Digital\u003c/stereo\u003e\n    \u003c/audio\u003e\n    \u003cpreviously-shown start=\"20220331180000 +0000\" channel=\"channel_two\" /\u003e\n    \u003cpremiere\u003eFirst time on British TV\u003c/premiere\u003e\n    \u003clast-chance lang=\"en\"\u003eLast time on this channel\u003c/last-chance\u003e\n    \u003cnew /\u003e\n    \u003csubtitles type=\"teletext\"\u003e\n      \u003clanguage\u003eEnglish\u003c/language\u003e\n    \u003c/subtitles\u003e\n    \u003csubtitles type=\"onscreen\"\u003e\n      \u003clanguage lang=\"en\"\u003eSpanish\u003c/language\u003e\n    \u003c/subtitles\u003e\n    \u003crating system=\"BBFC\"\u003e\n      \u003cvalue\u003e15\u003c/value\u003e\n      \u003cicon src=\"15_symbol.png\" /\u003e\n    \u003c/rating\u003e\n    \u003cstar-rating system=\"TV Guide\"\u003e\n      \u003cvalue\u003e 4/5\u003c/value\u003e\n      \u003cicon src=\"stars.png\" /\u003e\n    \u003c/star-rating\u003e\n    \u003creview type=\"text\" source=\"Rotten Tomatoes\" reviewer=\"Joe Bloggs\" lang=\"en\"\u003eThis is a fantastic show!\u003c/review\u003e\n    \u003creview type=\"url\" source=\"Rotten Tomatoes\" reviewer=\"Joe Bloggs\" lang=\"en\"\u003ehttps://example.com/programme_one_review\u003c/review\u003e\n    \u003cimage type=\"poster\" size=\"1\" orient=\"P\" system=\"tvdb\"\u003ehttps://tvdb.com/programme_one_poster_1.jpg\u003c/image\u003e\n    \u003cimage type=\"backdrop\" size=\"3\" orient=\"L\" system=\"tvdb\"\u003e https://tvdb.com/programme_one_backdrop_3.jpg\u003c/image\u003e\n  \u003c/programme\u003e\n  \u003cprogramme start=\"20220331180000 +0000\"\n    channel=\"channel_one\"\u003e\n    \u003ctitle\u003eProgramme Two: The minimum valid programme\u003c/title\u003e\n  \u003c/programme\u003e\n\u003c/tv\u003e\n```\n\n\u003c/details\u003e\n\n```typescript\nconst xml = `...`; // XMLTV file contents\nconst xmltv: Xmltv = parseXmltv(xml);\nconst programmes: XmltvProgramme[] = xmltv.programmes;\nconst channels: XmltvChannel[] = xmltv.channels;\n```\n\n\u003cdetails\u003e\n  \u003csummary\u003eExample output of `parseXmltv()`\u003c/summary\u003e\n\n```typescript\n{\n  channels: [\n    {\n      displayName: [\n        {\n          _value: \"Channel One\",\n          lang: \"en\",\n        },\n      ],\n      icon: [\n        {\n          height: 100,\n          src: \"https://example.com/channel_one_icon.jpg\",\n          width: 100,\n        },\n      ],\n      id: \"channel_one\",\n      url: [\n        {\n          _value: \"https://example.com/channel_one\",\n          system: \"example\",\n        },\n        {\n          _value: \"https://example.com/channel_one_alternate\",\n          system: \"other_system\",\n        },\n      ],\n    },\n    {\n      displayName: [\n        {\n          _value: \"Channel Two: Minimum valid channel\",\n        },\n      ],\n      id: \"channel_two\",\n    },\n  ],\n  date: new Date(\"2022-04-01T00:00:00.000Z\"),\n  generatorInfoName: \"Example Generator\",\n  generatorInfoUrl: \"example generator url\",\n  programmes: [\n    {\n      audio: {\n        present: true,\n        stereo: \"Dolby Digital\",\n      },\n      category: [\n        {\n          _value: \"Crime\",\n          lang: \"en\",\n        },\n        {\n          _value: \"Drama\",\n          lang: \"en\",\n        },\n      ],\n      channel: \"channel_one\",\n      clumpidx: \"0/1\",\n      country: {\n        _value: \"US\",\n      },\n      credits: {\n        actor: [\n          {\n            _value: \"David Thompson\",\n            role: \"Walter Johnson\",\n          },\n          {\n            _value: \"Ryan Lee\",\n            guest: true,\n            image: [\n              {\n                _value: \"https://www.example.com/xxx.jpg\",\n                type: \"person\",\n              },\n            ],\n            role: \"Karl James\",\n            url: [\n              {\n                _value: \"https://www.example.com/person/204\",\n                system: \"moviedb\",\n              },\n            ],\n          },\n        ],\n        adapter: [\n          {\n            _value: \"William Brown\",\n          },\n        ],\n        commentator: [\n          {\n            _value: \"James Wilson\",\n          },\n        ],\n        composer: [\n          {\n            _value: \"Max Wright\",\n          },\n        ],\n        director: [\n          {\n            _value: \"Samuel Jones\",\n          },\n        ],\n        editor: [\n          {\n            _value: \"Nora Peterson\",\n          },\n        ],\n        guest: [\n          {\n            _value: \"Lucas Martin\",\n          },\n          {\n            _value: \"Emily Parker\",\n          },\n          {\n            _value: \"Oliver Nelson\",\n          },\n        ],\n        presenter: [\n          {\n            _value: \"Amanda Johnson\",\n          },\n        ],\n        producer: [\n          {\n            _value: \"Emily Davis\",\n          },\n        ],\n        writer: [\n          {\n            _value: \"Samuel Jones\",\n          },\n        ],\n      },\n      date: new Date(\"2022-04-01T00:00:00.000Z\"),\n      desc: [\n        {\n          _value:\n            \"This programme entry showcases all possible features of the DTD\",\n          lang: \"en\",\n        },\n      ],\n      episodeNum: [\n        {\n          _value: \"S01E01\",\n          system: \"onscreen\",\n        },\n        {\n          _value: \"1.1.\",\n          system: \"xmltv_ns\",\n        },\n      ],\n      icon: [\n        {\n          height: 100,\n          src: \"https://example.com/programme_one_icon.jpg\",\n          width: 100,\n        },\n      ],\n      image: [\n        {\n          _value: \"https://tvdb.com/programme_one_poster_1.jpg\",\n          orient: \"P\",\n          size: 1,\n          system: \"tvdb\",\n          type: \"poster\",\n        },\n        {\n          _value: \"https://tvdb.com/programme_one_backdrop_3.jpg\",\n          orient: \"L\",\n          size: 3,\n          system: \"tvdb\",\n          type: \"backdrop\",\n        },\n      ],\n      keyword: [\n        {\n          _value: \"methamphetamine\",\n          lang: \"en\",\n        },\n        {\n          _value: \"cancer\",\n          lang: \"en\",\n        },\n      ],\n      language: {\n        _value: \"English\",\n      },\n      lastChance: {\n        _value: \"Last time on this channel\",\n        lang: \"en\",\n      },\n      length: {\n        _value: 60,\n        units: \"minutes\",\n      },\n      new: true,\n      origLanguage: {\n        _value: \"French\",\n        lang: \"en\",\n      },\n      pdcStart: new Date(\"2022-03-31T18:00:00.000Z\"),\n      premiere: {\n        _value: \"First time on British TV\",\n      },\n      previouslyShown: {\n        channel: \"channel_two\",\n        start: new Date(\"2022-03-31T18:00:00.000Z\"),\n      },\n      rating: [\n        {\n          icon: [\n            {\n              src: \"15_symbol.png\",\n            },\n          ],\n          system: \"BBFC\",\n          value: \"15\",\n        },\n      ],\n      review: [\n        {\n          _value: \"This is a fantastic show!\",\n          lang: \"en\",\n          reviewer: \"Joe Bloggs\",\n          source: \"Rotten Tomatoes\",\n          type: \"text\",\n        },\n        {\n          _value: \"https://example.com/programme_one_review\",\n          lang: \"en\",\n          reviewer: \"Joe Bloggs\",\n          source: \"Rotten Tomatoes\",\n          type: \"url\",\n        },\n      ],\n      showview: \"12345\",\n      starRating: [\n        {\n          icon: [\n            {\n              src: \"stars.png\",\n            },\n          ],\n          system: \"TV Guide\",\n          value: \"4/5\",\n        },\n      ],\n      start: new Date(\"2022-03-31T18:00:00.000Z\"),\n      stop: new Date(\"2022-03-31T19:00:00.000Z\"),\n      subTitle: [\n        {\n          _value: \"Pilot\",\n          lang: \"en\",\n        },\n      ],\n      subtitles: [\n        {\n          language: {\n            _value: \"English\",\n          },\n          type: \"teletext\",\n        },\n        {\n          language: {\n            _value: \"Spanish\",\n            lang: \"en\",\n          },\n          type: \"onscreen\",\n        },\n      ],\n      title: [\n        {\n          _value: \"Programme One\",\n          lang: \"en\",\n        },\n      ],\n      url: [\n        {\n          _value: \"https://example.com/programme_one\",\n          system: \"tvdb\",\n        },\n        {\n          _value: \"https://example.com/programme_one_2\",\n        },\n      ],\n      video: {\n        aspect: \"16:9\",\n        colour: false,\n        present: true,\n        quality: \"HDTV\",\n      },\n      videoplus: \"67890\",\n      vpsStart: new Date(\"2022-03-31T18:00:00.000Z\"),\n    },\n    {\n      channel: \"channel_one\",\n      start: new Date(\"2022-03-31T18:00:00.000Z\"),\n      title: [\n        {\n          _value: \"Programme Two: The minimum valid programme\",\n        },\n      ],\n    },\n  ],\n  sourceDataUrl: \"example.com/a\",\n  sourceInfoName: \"example\",\n  sourceInfoUrl: \"example.com\",\n};\n\n```\n\n\u003c/details\u003e\n\nYou can also generate an XMLTV file from an `Xmltv` tree:\n\n```typescript\nconst xml = writeXmltv(xmltvObject);\nconsole.log(xml); // \u003ctv\u003e...\u003c/tv\u003e\n```\n\nOr from a XMLTV DOM tree:\n\n```typescript\nconst xml = writeXmltv(xmltvDom, { fromDom: true });\nconsole.log(xml); // \u003ctv\u003e...\u003c/tv\u003e\n```\n\nIf you want to go even faster you can parse the file into a DOM tree and then traverse it yourself:\n\n```typescript\nconst xml = '...'; // XMLTV file contents\nconst parsed = parseXmltv(xml, { asDom: true });\n// or import { parser } from '@iptv/xmltv';\n// const parsed = parser(xml);\n\n// `parsed` is now a list of XmltvNode objects\n// which can be traversed using the `children` property\n// and attributes can be accessed using the `attributes` property\n// (see the XmltvNode interface for more details)\n\n// this is not the most efficient way to do this, but it's a good example\nconst programmes = parsed\n  .find((node) =\u003e {\n    // find the \u003ctv\u003e tag\n    return node.tagName === 'tv';\n  })\n  .children.filter((node) =\u003e {\n    // filter it's children for \u003cprogramme\u003e tags\n    return node.tagName === 'programme';\n  })\n  .map((programme) =\u003e {\n    // return a Programme object for each \u003cprogramme\u003e tag\n    return {\n      title: programme.children.find((t) =\u003e t.tagName === 'title').children[0],\n      start: new Date(programme.attributes.start),\n      stop: new Date(programme.attributes.stop),\n      channel: programme.attributes.channel,\n    };\n  });\n```\n\n---\n\n## ⚡ Performance\n\nThis 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](https://www.npmjs.com/package/epg-parser) and [xmltv](https://www.npmjs.com/package/xmltv). It also beats [fast-xml-parser](https://www.npmjs.com/package/fast-xml-parser).\n\nThe speed of this library is down to the implementation of the XML DOM tree parser [tXml](https://www.npmjs.com/package/txml). To learn more about the optimisations made by tXml please read [this blog post](https://tnickel.de/2020/08/30/2020-08-how-the-fastest-xml-parser-is-build/) by [@TobiasNickel](https://github.com/TobiasNickel).\n\n### Benchmarks\n\n\u003cpicture\u003e\n  \u003cimg src=\"ludicrous.gif\" /\u003e\n\u003c/picture\u003e\n\n#### Parsing XMLTV file (c1-p1.xml)\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n        \u003cth align=\"left\"\u003e\u003c/th\u003e\n        \u003cth align=\"left\"\u003eLibrary\u003c/th\u003e\n        \u003cth align=\"left\"\u003eOps/sec\u003c/th\u003e\n      \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003cth\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003e@iptv/xmltv\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e1,094,286\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth\u003e🟢\u003c/th\u003e\n      \u003cth align=\"left\"\u003e@iptv/xmltv (DOM only)\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e1,246,439\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003efast-xml-parser\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e426,947\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth\u003e🔴\u003c/th\u003e\n      \u003cth align=\"left\"\u003eepg-parser\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e96,468\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003exmltv\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e14,750\u003c/td\u003e\n    \u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n#### Writing XMLTV file (c1-p1.xml)\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003eLibrary\u003c/th\u003e\n      \u003cth align=\"left\"\u003eOps/sec\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e🟢\u003c/th\u003e\n      \u003cth align=\"left\"\u003e@iptv/xmltv\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e2,920,103\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e🔴\u003c/th\u003e\n      \u003cth align=\"left\"\u003efast-xml-parser\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e1,257,938\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n#### Time spent parsing different XMLTV files\n\n\u003ctable\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003eChannels\u003c/th\u003e\n      \u003cth align=\"right\"\u003e1\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e1\u003c/th\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e\u003c/th\u003e\n      \u003cth align=\"left\"\u003eProgrammes\u003c/th\u003e\n      \u003cth align=\"right\"\u003e0\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100\u003c/th\u003e\n      \u003cth align=\"right\"\u003e10,000\u003c/th\u003e\n      \u003cth align=\"right\"\u003e100,000\u003c/th\u003e\n      \u003cth align=\"right\"\u003e250,000\u003c/th\u003e\n      \u003cth align=\"right\"\u003e500,000\u003c/th\u003e\n      \u003cth align=\"right\"\u003e1,000,000\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e🟢\u003c/th\u003e\n      \u003cth align=\"left\"\u003e@iptv/xmltv\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e~60 μs\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~1.24 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~39 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~342 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~980 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~2.15 s\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~5.37 s\u003c/td\u003e\n    \u003c/tr\u003e\n    \u003ctr\u003e\n      \u003cth align=\"left\"\u003e🔴\u003c/th\u003e\n      \u003cth align=\"left\"\u003eepg-parser\u003c/th\u003e\n      \u003ctd align=\"right\"\u003e~362 μs\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~9.83 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~256 ms\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~2.25 s\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~6.26 s\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~13 s\u003c/td\u003e\n      \u003ctd align=\"right\"\u003e~28 s\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003cp\u003e\u003csup\u003eI used nanobench to get the above times. Nanobench doesn't support the xmltv's event based architecture, so is not included in file parsing timings.\u003c/sup\u003e\u003c/p\u003e\n\n\u003cp\u003e\u003csup\u003eThese benchmarks were run on a 2021 MacBook Pro M1 Max (10 cores) with 64 GB of RAM.\u003c/sup\u003e\u003c/p\u003e\n\n---\n\n## 🎯 Future Goals\n\n### Worker Support\n\nEven 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.\n\n### Streaming Support\n\nMy initial intent writing this library was to build a streaming parser, however I found the approach of [tXml](https://github.com/TobiasNickel/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.\n\n### CLI Module\n\nA command line program that can be piped around to convert files from one format to another.\n\n## 🚫 Non-Goals\n\n### Generic XML Parsing\n\nThis 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](https://github.com/TobiasNickel/txml) library instead.\n\n### Altering the Shape of the Data\n\nThe shape of the `Xmltv` type is designed to match the [XMLTV DTD](https://raw.githubusercontent.com/XMLTV/xmltv/master/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.\n\n---\n\n## 🤝 Contributing\n\nContributions are welcome! Even better if they align with the [future goals](#-future-goals).\n\nYou'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.\n\nTo be accepted your PR must pass all tests and not negatively impact the benchmarks. Some commands to help you:\n\n- `pnpm run test` - Run the vitest suite\n- `pnpm run benny` - Run additional benchmarks\n- `pnpm run benchmark` - Run the benchmarks with vitest\n- `pnpm run nanobench` - Run additional benchmarks\n\nThis project uses [Changesets](https://github.com/changesets/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](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).\n\n## 📄 License \u0026 Credit\n\nThis library is licensed under the [MIT License](https://github.com/ektotv/xmltv/LICENSE.md) and is free to use in both open source and commercial projects.\n\nThe parser is based on the [tXml](https://github.com/TobiasNickel/txml) library by [@TobiasNickel](https://github.com/TobiasNickel).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fektotv%2Fxmltv","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fektotv%2Fxmltv","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fektotv%2Fxmltv/lists"}