epg-grabber 0.46.1 → 0.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierrc.js +10 -0
- package/README.md +41 -60
- package/dist/cli.js +3 -2
- package/dist/{index-Bnw63KMN.js → index-Dm69fQTU.js} +4 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +7 -3
- package/src/cli.ts +2 -2
- package/src/index.ts +3 -7
- package/src/models/channel.ts +2 -2
- package/tests/__data__/expected/channels_array.guide.xml +4 -4
- package/tests/__data__/expected/example.guide.xml +2 -2
- package/tests/__data__/expected/fr/1TV.com.xml +1 -1
- package/tests/__data__/expected/index.guide.xml +7 -0
- package/tests/__data__/expected/mini.guide.xml +2 -2
- package/tests/__data__/expected/mini.guide.xml.gz +0 -0
- package/tests/__data__/expected/undefined/2TV.com.xml +1 -1
- package/tests/__data__/expected/wildcard.guide.xml +4 -4
- package/tests/index.test.ts +6 -4
- package/tests/__data__/output/channels_array.guide.xml +0 -14
package/.prettierrc.js
ADDED
package/README.md
CHANGED
|
@@ -8,61 +8,6 @@ Node.js CLI tool for grabbing EPG from different websites.
|
|
|
8
8
|
npm install -g epg-grabber
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```sh
|
|
14
|
-
epg-grabber --config=example.com.config.js
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
#### example.com.config.js
|
|
18
|
-
|
|
19
|
-
```js
|
|
20
|
-
module.exports = {
|
|
21
|
-
site: 'example.com',
|
|
22
|
-
channels: 'example.com.channels.xml',
|
|
23
|
-
url: function (context) {
|
|
24
|
-
const { date, channel } = context
|
|
25
|
-
|
|
26
|
-
return `https://api.example.com/${date.format('YYYY-MM-DD')}/channel/${channel.site_id}`
|
|
27
|
-
},
|
|
28
|
-
parser: function (context) {
|
|
29
|
-
const programs = JSON.parse(context.content)
|
|
30
|
-
|
|
31
|
-
return programs.map(program => {
|
|
32
|
-
return {
|
|
33
|
-
title: program.title,
|
|
34
|
-
start: program.start,
|
|
35
|
-
stop: program.stop
|
|
36
|
-
}
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
#### example.com.channels.xml
|
|
43
|
-
|
|
44
|
-
```xml
|
|
45
|
-
<?xml version="1.0" ?>
|
|
46
|
-
<channels site="example.com">
|
|
47
|
-
<channel site_id="cnn-23" xmltv_id="CNN.us">CNN</channel>
|
|
48
|
-
</channels>
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Example Output
|
|
52
|
-
|
|
53
|
-
```xml
|
|
54
|
-
<tv>
|
|
55
|
-
<channel id="CNN.us">
|
|
56
|
-
<display-name>CNN</display-name>
|
|
57
|
-
<url>https://example.com</url>
|
|
58
|
-
</channel>
|
|
59
|
-
<programme start="20211116040000 +0000" stop="20211116050000 +0000" channel="CNN.us">
|
|
60
|
-
<title lang="en">News at 10PM</title>
|
|
61
|
-
</programme>
|
|
62
|
-
// ...
|
|
63
|
-
</tv>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
11
|
## CLI
|
|
67
12
|
|
|
68
13
|
```sh
|
|
@@ -86,7 +31,15 @@ Arguments:
|
|
|
86
31
|
- `--log`: path to log file (optional)
|
|
87
32
|
- `--log-level`: set the log level (default: `info`)
|
|
88
33
|
|
|
89
|
-
##
|
|
34
|
+
## How to use?
|
|
35
|
+
|
|
36
|
+
First, you need to create two files:
|
|
37
|
+
|
|
38
|
+
<details>
|
|
39
|
+
<summary>example.com.config.js</summary>
|
|
40
|
+
<br>
|
|
41
|
+
|
|
42
|
+
This file describes what kind of request we need to send to get the guide for a particular channel on a certain date and how to parse the response.
|
|
90
43
|
|
|
91
44
|
```js
|
|
92
45
|
module.exports = {
|
|
@@ -182,14 +135,14 @@ module.exports = {
|
|
|
182
135
|
}
|
|
183
136
|
```
|
|
184
137
|
|
|
185
|
-
|
|
138
|
+
### Request Context Object
|
|
186
139
|
|
|
187
140
|
Inside `url()`, `logo()`, `request.data()`, `request.headers()` functions in `config.js` you can access a `context` object containing the following data:
|
|
188
141
|
|
|
189
142
|
- `channel`: The object describing the current channel (xmltv_id, site_id, name, lang)
|
|
190
143
|
- `date`: The 'dayjs' instance with the requested date
|
|
191
144
|
|
|
192
|
-
|
|
145
|
+
### Parser Context Object
|
|
193
146
|
|
|
194
147
|
Inside `parser()` function in `config.js` you can access a `context` object containing the following data:
|
|
195
148
|
|
|
@@ -201,7 +154,7 @@ Inside `parser()` function in `config.js` you can access a `context` object cont
|
|
|
201
154
|
- `request`: The request config
|
|
202
155
|
- `cached`: A boolean to check whether this request was cached or not
|
|
203
156
|
|
|
204
|
-
|
|
157
|
+
### Program Object
|
|
205
158
|
|
|
206
159
|
| Property | Aliases | Type | Required |
|
|
207
160
|
| --------------- | -------------------------------- | ------------------------------------------------ | -------- |
|
|
@@ -371,7 +324,13 @@ Example:
|
|
|
371
324
|
}
|
|
372
325
|
```
|
|
373
326
|
|
|
374
|
-
|
|
327
|
+
</details>
|
|
328
|
+
|
|
329
|
+
<details>
|
|
330
|
+
<summary>example.com.channels.xml</summary>
|
|
331
|
+
<br>
|
|
332
|
+
|
|
333
|
+
This file contains a list of channels available at the source.
|
|
375
334
|
|
|
376
335
|
```xml
|
|
377
336
|
<?xml version="1.0" ?>
|
|
@@ -395,6 +354,28 @@ You can also specify the language, site, url, logo and LCN (Logical Channel Numb
|
|
|
395
354
|
>France 24</channel>
|
|
396
355
|
```
|
|
397
356
|
|
|
357
|
+
</details>
|
|
358
|
+
|
|
359
|
+
After that, you just need to run the grabber with path to the config file:
|
|
360
|
+
|
|
361
|
+
```sh
|
|
362
|
+
epg-grabber --config=path/to/example.com.config.js
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
And when the download is complete, a ready-to-use guide will appear in the location you specified:
|
|
366
|
+
|
|
367
|
+
```xml
|
|
368
|
+
<tv>
|
|
369
|
+
<channel id="CNN.us">
|
|
370
|
+
<display-name>CNN</display-name>
|
|
371
|
+
</channel>
|
|
372
|
+
<programme start="20211116040000 +0000" stop="20211116050000 +0000" channel="CNN.us">
|
|
373
|
+
<title lang="en">News at 10PM</title>
|
|
374
|
+
</programme>
|
|
375
|
+
// ...
|
|
376
|
+
</tv>
|
|
377
|
+
```
|
|
378
|
+
|
|
398
379
|
## How to use SOCKS proxy?
|
|
399
380
|
|
|
400
381
|
```
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as name, v as version, d as description, p as parseNumber, l as loadJs, a as parseProxy, E as EPGGrabberMock, b as EPGGrabber, c as defaultConfig, i as isObject, g as getAbsPath, e as getUTCDate } from './index-
|
|
2
|
+
import { n as name, v as version, d as description, p as parseNumber, l as loadJs, a as parseProxy, E as EPGGrabberMock, b as EPGGrabber, c as defaultConfig, i as isObject, g as getAbsPath, e as getUTCDate } from './index-Dm69fQTU.js';
|
|
3
3
|
import { Collection, Template } from '@freearhey/core';
|
|
4
4
|
import { Command, Option } from 'commander';
|
|
5
5
|
import { SocksProxyAgent } from 'socks-proxy-agent';
|
|
@@ -220,7 +220,8 @@ async function main() {
|
|
|
220
220
|
})
|
|
221
221
|
);
|
|
222
222
|
await Promise$1.all(requests.all());
|
|
223
|
-
const
|
|
223
|
+
const headers = { date: utcDate.format("YYYYMMDD") };
|
|
224
|
+
const xml = EPGGrabber.generateXMLTV(groupChannels.all(), programs.all(), headers);
|
|
224
225
|
const channelSample = groupChannels.sample();
|
|
225
226
|
let outputPath = template.format(channelSample.toObject());
|
|
226
227
|
const outputDir = path$1.dirname(outputPath);
|
|
@@ -35,9 +35,6 @@ function parseNumber(value) {
|
|
|
35
35
|
function sleep(ms) {
|
|
36
36
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
37
|
}
|
|
38
|
-
function isDate(date) {
|
|
39
|
-
return dayjs(date).isValid();
|
|
40
|
-
}
|
|
41
38
|
function isObject(value) {
|
|
42
39
|
return !!value && value.constructor === Object;
|
|
43
40
|
}
|
|
@@ -65,9 +62,6 @@ function escapeString(value, defaultValue = "") {
|
|
|
65
62
|
function formatDate(date, format) {
|
|
66
63
|
return date ? dayjs.utc(date).format(format) : "";
|
|
67
64
|
}
|
|
68
|
-
function toURL(domain) {
|
|
69
|
-
return domain ? `https://${domain}` : "";
|
|
70
|
-
}
|
|
71
65
|
function createXMLElement(name, attrs, children) {
|
|
72
66
|
return convertXMLElementToString({ name, attrs, children });
|
|
73
67
|
}
|
|
@@ -102,7 +96,7 @@ function toArray(value) {
|
|
|
102
96
|
}
|
|
103
97
|
|
|
104
98
|
var name = "epg-grabber";
|
|
105
|
-
var version = "0.
|
|
99
|
+
var version = "0.47.0";
|
|
106
100
|
var description = "Node.js CLI tool for grabbing EPG from different sites";
|
|
107
101
|
var homepage = "https://github.com/freearhey/epg-grabber";
|
|
108
102
|
|
|
@@ -145,7 +139,7 @@ class Channel {
|
|
|
145
139
|
this.site_id = data.site_id;
|
|
146
140
|
this.lang = data.lang;
|
|
147
141
|
this.logo = data.logo;
|
|
148
|
-
this.url = data.url
|
|
142
|
+
this.url = data.url;
|
|
149
143
|
this.lcn = data.lcn;
|
|
150
144
|
this.index = data.index !== void 0 ? data.index : -1;
|
|
151
145
|
}
|
|
@@ -799,18 +793,15 @@ class EPGGrabber {
|
|
|
799
793
|
).filter(Boolean);
|
|
800
794
|
return channels;
|
|
801
795
|
}
|
|
802
|
-
static generateXMLTV(channels, programs,
|
|
796
|
+
static generateXMLTV(channels, programs, headers) {
|
|
803
797
|
if (!channels.every((channel) => channel instanceof Channel)) {
|
|
804
798
|
throw new Error('"channels" must be an array of Channels');
|
|
805
799
|
}
|
|
806
800
|
if (!programs.every((program) => program instanceof Program)) {
|
|
807
801
|
throw new Error('"programs" must be an array of Programs');
|
|
808
802
|
}
|
|
809
|
-
if (!isDate(date)) {
|
|
810
|
-
throw new Error('"date" must be a valid date');
|
|
811
|
-
}
|
|
812
803
|
let output = `<?xml version="1.0" encoding="UTF-8" ?>`;
|
|
813
|
-
output += createXMLElement("tv",
|
|
804
|
+
output += createXMLElement("tv", headers, [
|
|
814
805
|
...channels.map((channel) => "\r\n" + channel.toXML()),
|
|
815
806
|
...programs.map((program) => "\r\n" + program.toXML()),
|
|
816
807
|
"\r\n"
|
package/dist/index.d.ts
CHANGED
|
@@ -710,7 +710,7 @@ declare class EPGGrabber {
|
|
|
710
710
|
loadLogo(channel: Channel, date: string | number | Date | Dayjs | null, config?: SiteConfig): Promise<string | null>;
|
|
711
711
|
grab(channel: Channel, date: string | number | Date | Dayjs | null, config?: SiteConfig | GrabCallback, callback?: GrabCallback): Promise<Program[]>;
|
|
712
712
|
static parseChannelsXML(xml: string): Channel[];
|
|
713
|
-
static generateXMLTV(channels: Channel[], programs: Program[],
|
|
713
|
+
static generateXMLTV(channels: Channel[], programs: Program[], headers?: Record<string, string>): string;
|
|
714
714
|
}
|
|
715
715
|
declare class EPGGrabberMock extends EPGGrabber {
|
|
716
716
|
grab(channel: Channel, date: string | number | Date | Dayjs | null, config?: SiteConfig | GrabCallback, callback?: GrabCallback): Promise<Program[]>;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export { C as Channel, b as EPGGrabber, E as EPGGrabberMock, P as Program } from './index-
|
|
2
|
+
export { C as Channel, b as EPGGrabber, E as EPGGrabberMock, P as Program } from './index-Dm69fQTU.js';
|
|
3
3
|
import 'axios-mock-adapter';
|
|
4
4
|
import 'lodash.merge';
|
|
5
5
|
import 'xml-js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "epg-grabber",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Node.js CLI tool for grabbing EPG from different sites",
|
|
5
5
|
"homepage": "https://github.com/freearhey/epg-grabber",
|
|
6
6
|
"preferGlobal": true,
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"build": "pkgroll --clean-dist",
|
|
19
19
|
"dev": "pkgroll --watch",
|
|
20
20
|
"lint": "npx eslint ./src/**/*.ts ./tests/**/*.ts",
|
|
21
|
-
"test": "npx vitest run"
|
|
21
|
+
"test": "npx vitest run",
|
|
22
|
+
"prepublishOnly": "npm run build"
|
|
22
23
|
},
|
|
23
24
|
"publishConfig": {
|
|
24
25
|
"registry": "https://registry.npmjs.org/"
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"url": "https://github.com/freearhey/epg-grabber.git"
|
|
35
36
|
},
|
|
36
37
|
"engines": {
|
|
37
|
-
"node": ">=
|
|
38
|
+
"node": ">=20.20.0"
|
|
38
39
|
},
|
|
39
40
|
"dependencies": {
|
|
40
41
|
"@freearhey/core": "^0.14.0",
|
|
@@ -70,5 +71,8 @@
|
|
|
70
71
|
"typescript": "^5.9.2",
|
|
71
72
|
"typescript-eslint": "^8.44.1",
|
|
72
73
|
"vitest": "^3.2.4"
|
|
74
|
+
},
|
|
75
|
+
"overrides": {
|
|
76
|
+
"esbuild": "0.23.1"
|
|
73
77
|
}
|
|
74
78
|
}
|
package/src/cli.ts
CHANGED
|
@@ -12,7 +12,6 @@ import defaultConfig from './default.config'
|
|
|
12
12
|
import { Program, Channel } from './models'
|
|
13
13
|
import { Logger } from './core/logger'
|
|
14
14
|
import { SiteConfig } from './types'
|
|
15
|
-
import { AxiosHeaders } from 'axios'
|
|
16
15
|
import { TaskQueue } from 'cwait'
|
|
17
16
|
import merge from 'lodash.merge'
|
|
18
17
|
import Promise from 'bluebird'
|
|
@@ -265,7 +264,8 @@ async function main() {
|
|
|
265
264
|
|
|
266
265
|
await Promise.all(requests.all())
|
|
267
266
|
|
|
268
|
-
const
|
|
267
|
+
const headers = { date: utcDate.format('YYYYMMDD') }
|
|
268
|
+
const xml = EPGGrabber.generateXMLTV(groupChannels.all(), programs.all(), headers)
|
|
269
269
|
const channelSample = groupChannels.sample()
|
|
270
270
|
let outputPath = template.format(channelSample.toObject() as { [key: string]: any })
|
|
271
271
|
const outputDir = path.dirname(outputPath)
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sleep, getUTCDate, isPromise,
|
|
1
|
+
import { sleep, getUTCDate, isPromise, createXMLElement } from './core/utils'
|
|
2
2
|
import { ProgramParserResult } from './types/program'
|
|
3
3
|
import AxiosMockAdapter from 'axios-mock-adapter'
|
|
4
4
|
import { SiteConfig } from './types/siteConfig'
|
|
@@ -136,7 +136,7 @@ export class EPGGrabber {
|
|
|
136
136
|
static generateXMLTV(
|
|
137
137
|
channels: Channel[],
|
|
138
138
|
programs: Program[],
|
|
139
|
-
|
|
139
|
+
headers?: Record<string, string>
|
|
140
140
|
): string {
|
|
141
141
|
if (!channels.every((channel: Channel) => channel instanceof Channel)) {
|
|
142
142
|
throw new Error('"channels" must be an array of Channels')
|
|
@@ -146,12 +146,8 @@ export class EPGGrabber {
|
|
|
146
146
|
throw new Error('"programs" must be an array of Programs')
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
if (!isDate(date)) {
|
|
150
|
-
throw new Error('"date" must be a valid date')
|
|
151
|
-
}
|
|
152
|
-
|
|
153
149
|
let output = `<?xml version="1.0" encoding="UTF-8" ?>`
|
|
154
|
-
output += createXMLElement('tv',
|
|
150
|
+
output += createXMLElement('tv', headers, [
|
|
155
151
|
...channels.map((channel: Channel) => '\r\n' + channel.toXML()),
|
|
156
152
|
...programs.map((program: Program) => '\r\n' + program.toXML()),
|
|
157
153
|
'\r\n'
|
package/src/models/channel.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { escapeString, createXMLElement } from '../core/utils'
|
|
2
2
|
import { ChannelData } from '../types/channel'
|
|
3
3
|
import xmlJs from 'xml-js'
|
|
4
4
|
|
|
@@ -20,7 +20,7 @@ export class Channel {
|
|
|
20
20
|
this.site_id = data.site_id
|
|
21
21
|
this.lang = data.lang
|
|
22
22
|
this.logo = data.logo
|
|
23
|
-
this.url = data.url
|
|
23
|
+
this.url = data.url
|
|
24
24
|
this.lcn = data.lcn
|
|
25
25
|
this.index = data.index !== undefined ? data.index : -1
|
|
26
26
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="3TV.com"><display-name>3 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
3
|
-
<channel id="4TV.com"><display-name>4 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
4
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"
|
|
5
|
-
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
2
|
+
<channel id="3TV.com"><display-name>3 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
3
|
+
<channel id="4TV.com"><display-name>4 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
4
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/></channel>
|
|
5
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
6
6
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="3TV.com"><title>Program1</title></programme>
|
|
7
7
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="3TV.com"><title>Program1</title></programme>
|
|
8
8
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><
|
|
3
|
-
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><lcn>36</lcn></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
4
4
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
5
5
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
6
6
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><lcn>36</lcn></channel>
|
|
3
3
|
</tv>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?><tv date="20220505">
|
|
2
|
+
<channel id="1TV.co"><display-name>1 TV</display-name><icon src="https://example.com/channel_one_icon.jpg"/><url>https://example.com/channel_one?foo=foo&bar=bar</url><lcn>36</lcn></channel>
|
|
3
|
+
<channel id="2TV.co"><display-name>2 TV</display-name><icon src="https://example.com/logos/2TV.png"/></channel>
|
|
4
|
+
<channel id="3TV.co"><display-name>3 TV</display-name></channel>
|
|
5
|
+
<programme start="20210319060000 +0000" stop="20210319063000 +0000" channel="1TV.co"><title>Program 1</title><sub-title>Sub-title & 1</sub-title><desc>Description for Program 1</desc><credits><director>Director 1<url system="TestSystem">http://example.com/director1.html</url><image>https://example.com/image1.jpg</image><image type="person" size="2" orient="P" system="TestSystem">https://example.com/image2.jpg</image></director><director>Director 2</director><actor>Actor 1</actor><actor>Actor 2</actor><writer>Writer 1</writer></credits><date>20220506</date><category>Test</category><keyword lang="en">physical-comedy</keyword><keyword lang="en">romantic</keyword><language>English</language><orig-language lang="en">French</orig-language><length units="minutes">60</length><country>US</country><url>http://example.com/title.html</url><episode-num system="xmltv_ns">8.238.0/1</episode-num><episode-num system="onscreen">S09E239</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/><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="MPAA"><value>P&G</value><icon src="http://example.com/pg_symbol.png"/></rating><star-rating system="TV Guide"><value>4/5</value><icon src="stars.png"/></star-rating><star-rating system="IMDB"><value>8/10</value></star-rating><review type="text" source="Rotten Tomatoes" reviewer="Joe Bloggs" lang="en">This is a fantastic show!</review><review type="text" source="IDMB" reviewer="Jane Doe" lang="en">I love this 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?foo=foo&bar=bar</image><image type="poster" size="2" orient="P" system="tmdb">https://tmdb.com/programme_one_poster_2.jpg</image><image type="backdrop" size="3" orient="L" system="tvdb">https://tvdb.com/programme_one_backdrop_3.jpg</image><image type="backdrop" size="3" orient="L" system="tmdb">https://tmdb.com/programme_one_backdrop_3.jpg</image><icon src="https://example.com/images/Program1.png?x=шеллы&sid=777"/></programme>
|
|
6
|
+
<programme start="20210319060000 +0000" stop="20210319063000 +0000" channel="2TV.co"><title lang="es">Program 2</title></programme>
|
|
7
|
+
</tv>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><
|
|
3
|
-
<channel id="2TV.com"><display-name>2 TV</display-name
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><lcn>36</lcn></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name></channel>
|
|
4
4
|
</tv>
|
|
Binary file
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"
|
|
3
|
-
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
4
|
-
<channel id="3TV.com"><display-name>3 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
5
|
-
<channel id="4TV.com"><display-name>4 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
4
|
+
<channel id="3TV.com"><display-name>3 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
5
|
+
<channel id="4TV.com"><display-name>4 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/></channel>
|
|
6
6
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
7
7
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="4TV.com"><title>Program1</title></programme>
|
|
8
8
|
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="3TV.com"><title>Program1</title></programme>
|
package/tests/index.test.ts
CHANGED
|
@@ -7,8 +7,10 @@ import { EPGGrabber, EPGGrabberMock } from '../src/index'
|
|
|
7
7
|
import { SiteConfig } from '../src/types/siteConfig'
|
|
8
8
|
import * as epgGrabber from '../src/index'
|
|
9
9
|
import { http, HttpResponse } from 'msw'
|
|
10
|
+
import { pathToFileURL } from 'node:url'
|
|
10
11
|
import { setupServer } from 'msw/node'
|
|
11
12
|
import path from 'node:path'
|
|
13
|
+
import dayjs from 'dayjs'
|
|
12
14
|
import fs from 'fs-extra'
|
|
13
15
|
|
|
14
16
|
describe('EPGGrabber', () => {
|
|
@@ -444,11 +446,11 @@ describe('EPGGrabber', () => {
|
|
|
444
446
|
})
|
|
445
447
|
]
|
|
446
448
|
|
|
447
|
-
const output = EPGGrabber.generateXMLTV(channels, programs)
|
|
449
|
+
const output = EPGGrabber.generateXMLTV(channels, programs, { date: dayjs.utc().format('YYYYMMDD') })
|
|
448
450
|
|
|
449
|
-
expect(output).
|
|
450
|
-
|
|
451
|
-
|
|
451
|
+
expect(output).toEqual(
|
|
452
|
+
fs.readFileSync(pathToFileURL('tests/__data__/expected/index.guide.xml'), 'utf8')
|
|
453
|
+
)
|
|
452
454
|
})
|
|
453
455
|
})
|
|
454
456
|
})
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" ?><tv date="20251028">
|
|
2
|
-
<channel id="3TV.com"><display-name>3 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/><url>https://example2.com</url></channel>
|
|
3
|
-
<channel id="4TV.com"><display-name>4 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/><url>https://example2.com</url></channel>
|
|
4
|
-
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>
|
|
5
|
-
<channel id="2TV.com"><display-name>2 TV</display-name><icon src="http://example.com/logos/1TV.png?x=шеллы&sid=777"/><url>https://example.com</url></channel>
|
|
6
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="3TV.com"><title>Program1</title></programme>
|
|
7
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="3TV.com"><title>Program1</title></programme>
|
|
8
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
9
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
10
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
11
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
12
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="4TV.com"><title>Program1</title></programme>
|
|
13
|
-
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="4TV.com"><title>Program1</title></programme>
|
|
14
|
-
</tv>
|