epg-grabber 0.28.6 → 0.29.2
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/bin/epg-grabber.js +3 -0
- package/package.json +2 -1
- package/src/Program.js +25 -7
- package/src/index.js +4 -0
- package/src/parser.js +1 -8
- package/src/xmltv.js +12 -4
- package/tests/Program.test.js +86 -75
- package/tests/__data__/expected/duplicates.guide.xml +6 -0
- package/tests/{input → __data__/input}/async.config.js +0 -0
- package/tests/__data__/input/duplicates.config.js +18 -0
- package/tests/{input → __data__/input}/example.channels.xml +0 -0
- package/tests/{input → __data__/input}/example.config.js +0 -0
- package/tests/{input → __data__/input}/mini.config.js +0 -0
- package/tests/__data__/output/duplicates.guide.xml +6 -0
- package/tests/__data__/output/duplicates.guide.xml.gz +0 -0
- package/tests/__data__/output/mini.guide.xml +4 -0
- package/tests/__data__/output/mini.guide.xml.gz +0 -0
- package/tests/bin.test.js +36 -9
- package/tests/config.test.js +1 -1
- package/tests/index.test.js +5 -5
- package/tests/parser.test.js +5 -5
- package/tests/xmltv.test.js +12 -4
package/bin/epg-grabber.js
CHANGED
|
@@ -9,6 +9,7 @@ const { EPGGrabber, parseChannels, generateXMLTV } = require('../src/index')
|
|
|
9
9
|
const { create: createLogger } = require('../src/logger')
|
|
10
10
|
const { parseNumber, getUTCDate } = require('../src/utils')
|
|
11
11
|
const { name, version, description } = require('../package.json')
|
|
12
|
+
const _ = require('lodash')
|
|
12
13
|
const dayjs = require('dayjs')
|
|
13
14
|
const utc = require('dayjs/plugin/utc')
|
|
14
15
|
|
|
@@ -99,6 +100,8 @@ async function main() {
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
103
|
+
programs = _.uniqBy(programs, p => p.start + p.channel)
|
|
104
|
+
|
|
102
105
|
const xml = generateXMLTV({ channels, programs })
|
|
103
106
|
let outputPath = options.output || config.output
|
|
104
107
|
if (options.gzip) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "epg-grabber",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.2",
|
|
4
4
|
"description": "Node.js CLI tool for grabbing EPG from different sites",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"preferGlobal": true,
|
|
@@ -35,6 +35,7 @@
|
|
|
35
35
|
"commander": "^7.1.0",
|
|
36
36
|
"curl-generator": "^0.2.0",
|
|
37
37
|
"dayjs": "^1.10.4",
|
|
38
|
+
"epg-parser": "^0.1.6",
|
|
38
39
|
"glob": "^7.1.6",
|
|
39
40
|
"lodash": "^4.17.21",
|
|
40
41
|
"node-gzip": "^1.1.2",
|
package/src/Program.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
const { padStart } = require('lodash')
|
|
2
2
|
const { toArray, toUnix, parseNumber } = require('./utils')
|
|
3
|
+
const Channel = require('./Channel')
|
|
3
4
|
|
|
4
5
|
class Program {
|
|
5
|
-
constructor(p) {
|
|
6
|
+
constructor(p, c) {
|
|
7
|
+
if (!(c instanceof Channel)) {
|
|
8
|
+
throw new Error('The second argument in the constructor must be the "Channel" class')
|
|
9
|
+
}
|
|
10
|
+
|
|
6
11
|
const data = {
|
|
7
|
-
site: p.site || '',
|
|
8
|
-
channel: p.channel || '',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
+
site: p.site || c.site || '',
|
|
13
|
+
channel: p.channel || c.id || '',
|
|
14
|
+
titles: toArray(p.titles || p.title).map(text => toTextObject(text, c.lang)),
|
|
15
|
+
sub_titles: toArray(p.sub_titles || p.sub_title).map(text => toTextObject(text, c.lang)),
|
|
16
|
+
descriptions: toArray(p.descriptions || p.description || p.desc).map(text =>
|
|
17
|
+
toTextObject(text, c.lang)
|
|
18
|
+
),
|
|
12
19
|
icon: toIconObject(p.icon),
|
|
13
20
|
episodeNumbers: p.episodeNumbers || getEpisodeNumbers(p.season, p.episode),
|
|
14
21
|
date: p.date ? toUnix(p.date) : null,
|
|
@@ -16,7 +23,7 @@ class Program {
|
|
|
16
23
|
stop: p.stop ? toUnix(p.stop) : null,
|
|
17
24
|
urls: toArray(p.urls || p.url).map(toUrlObject),
|
|
18
25
|
ratings: toArray(p.ratings || p.rating).map(toRatingObject),
|
|
19
|
-
categories: toArray(p.categories || p.category),
|
|
26
|
+
categories: toArray(p.categories || p.category).map(text => toTextObject(text, c.lang)),
|
|
20
27
|
directors: toArray(p.directors || p.director).map(toPersonObject),
|
|
21
28
|
actors: toArray(p.actors || p.actor).map(toPersonObject),
|
|
22
29
|
writers: toArray(p.writers || p.writer).map(toPersonObject),
|
|
@@ -37,6 +44,17 @@ class Program {
|
|
|
37
44
|
|
|
38
45
|
module.exports = Program
|
|
39
46
|
|
|
47
|
+
function toTextObject(text, lang) {
|
|
48
|
+
if (typeof text === 'string') {
|
|
49
|
+
return { value: text, lang }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
value: text.value,
|
|
54
|
+
lang: text.lang
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
40
58
|
function toPersonObject(person) {
|
|
41
59
|
if (typeof person === 'string') {
|
|
42
60
|
return {
|
package/src/index.js
CHANGED
|
@@ -27,6 +27,10 @@ class EPGGrabber {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
async grab(channel, date, cb = () => {}) {
|
|
30
|
+
if (!(channel instanceof Channel)) {
|
|
31
|
+
throw new Error('The first argument must be the "Channel" class')
|
|
32
|
+
}
|
|
33
|
+
|
|
30
34
|
await sleep(this.config.delay)
|
|
31
35
|
|
|
32
36
|
date = typeof date === 'string' ? getUTCDate(date) : date
|
package/src/parser.js
CHANGED
|
@@ -41,12 +41,5 @@ async function parsePrograms(data) {
|
|
|
41
41
|
throw new Error('Parser should return an array')
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
return programs
|
|
45
|
-
.filter(i => i)
|
|
46
|
-
.map(p => {
|
|
47
|
-
p.site = channel.site
|
|
48
|
-
p.channel = p.channel || channel.id
|
|
49
|
-
|
|
50
|
-
return new Program(p)
|
|
51
|
-
})
|
|
44
|
+
return programs.filter(i => i).map(p => new Program(p, channel))
|
|
52
45
|
}
|
package/src/xmltv.js
CHANGED
|
@@ -47,9 +47,15 @@ function createElements(channels, programs, date) {
|
|
|
47
47
|
channel: program.channel
|
|
48
48
|
},
|
|
49
49
|
[
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
...program.titles.map(title =>
|
|
51
|
+
el('title', { lang: title.lang }, [escapeString(title.value)])
|
|
52
|
+
),
|
|
53
|
+
...program.sub_titles.map(sub_title =>
|
|
54
|
+
el('sub-title', { lang: sub_title.lang }, [escapeString(sub_title.value)])
|
|
55
|
+
),
|
|
56
|
+
...program.descriptions.map(desc =>
|
|
57
|
+
el('desc', { lang: desc.lang }, [escapeString(desc.value)])
|
|
58
|
+
),
|
|
53
59
|
el('credits', {}, [
|
|
54
60
|
...program.directors.map(data => createCastMember('director', data)),
|
|
55
61
|
...program.actors.map(data => createCastMember('actor', data)),
|
|
@@ -63,7 +69,9 @@ function createElements(channels, programs, date) {
|
|
|
63
69
|
...program.guests.map(data => createCastMember('guest', data))
|
|
64
70
|
]),
|
|
65
71
|
el('date', {}, [formatDate(program.date, 'YYYYMMDD')]),
|
|
66
|
-
...program.categories.map(category =>
|
|
72
|
+
...program.categories.map(category =>
|
|
73
|
+
el('category', { lang: category.lang }, [escapeString(category.value)])
|
|
74
|
+
),
|
|
67
75
|
el('icon', { src: program.icon.src }),
|
|
68
76
|
...program.urls.map(createURL),
|
|
69
77
|
...program.episodeNumbers.map(episode =>
|
package/tests/Program.test.js
CHANGED
|
@@ -1,61 +1,65 @@
|
|
|
1
1
|
import Channel from '../src/Channel'
|
|
2
2
|
import Program from '../src/Program'
|
|
3
3
|
|
|
4
|
-
const channel = new Channel({ xmltv_id: '1tv', lang: '
|
|
4
|
+
const channel = new Channel({ xmltv_id: '1tv', lang: 'fr', site: 'example.com' })
|
|
5
5
|
|
|
6
6
|
it('can create new Program', () => {
|
|
7
|
-
const program = new Program(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
7
|
+
const program = new Program(
|
|
8
|
+
{
|
|
9
|
+
title: 'Title',
|
|
10
|
+
sub_title: 'Subtitle',
|
|
11
|
+
description: 'Description',
|
|
12
|
+
icon: 'https://example.com/image.jpg',
|
|
13
|
+
season: 9,
|
|
14
|
+
episode: 238,
|
|
15
|
+
date: '20220506',
|
|
16
|
+
start: 1616133600000,
|
|
17
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
18
|
+
url: 'http://example.com/title.html',
|
|
19
|
+
category: ['Category1', 'Category2'],
|
|
20
|
+
rating: {
|
|
21
|
+
system: 'MPAA',
|
|
22
|
+
value: 'PG',
|
|
23
|
+
icon: 'http://example.com/pg_symbol.png'
|
|
24
|
+
},
|
|
25
|
+
directors: 'Director1',
|
|
26
|
+
actors: [
|
|
27
|
+
'Actor1',
|
|
28
|
+
{ value: 'Actor2', url: 'http://actor2.com', image: 'http://actor2.com/image.png' }
|
|
29
|
+
],
|
|
30
|
+
writer: {
|
|
31
|
+
value: 'Writer1',
|
|
32
|
+
url: { system: 'imdb', value: 'http://imdb.com/p/writer1' },
|
|
33
|
+
image: {
|
|
34
|
+
value: 'https://example.com/image.jpg',
|
|
35
|
+
type: 'person',
|
|
36
|
+
size: '2',
|
|
37
|
+
system: 'TestSystem',
|
|
38
|
+
orient: 'P'
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
adapters: [
|
|
42
|
+
{
|
|
43
|
+
value: 'Adapter1',
|
|
44
|
+
url: ['http://imdb.com/p/adapter1', 'http://imdb.com/p/adapter2'],
|
|
45
|
+
image: ['https://example.com/image1.jpg', 'https://example.com/image2.jpg']
|
|
46
|
+
}
|
|
47
|
+
]
|
|
41
48
|
},
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
value: 'Adapter1',
|
|
45
|
-
url: ['http://imdb.com/p/adapter1', 'http://imdb.com/p/adapter2'],
|
|
46
|
-
image: ['https://example.com/image1.jpg', 'https://example.com/image2.jpg']
|
|
47
|
-
}
|
|
48
|
-
]
|
|
49
|
-
})
|
|
49
|
+
channel
|
|
50
|
+
)
|
|
50
51
|
|
|
51
52
|
expect(program).toMatchObject({
|
|
52
53
|
site: 'example.com',
|
|
53
54
|
channel: '1tv',
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
titles: [{ value: 'Title', lang: 'fr' }],
|
|
56
|
+
sub_titles: [{ value: 'Subtitle', lang: 'fr' }],
|
|
57
|
+
descriptions: [{ value: 'Description', lang: 'fr' }],
|
|
57
58
|
urls: [{ system: '', value: 'http://example.com/title.html' }],
|
|
58
|
-
categories: [
|
|
59
|
+
categories: [
|
|
60
|
+
{ value: 'Category1', lang: 'fr' },
|
|
61
|
+
{ value: 'Category2', lang: 'fr' }
|
|
62
|
+
],
|
|
59
63
|
icon: { src: 'https://example.com/image.jpg' },
|
|
60
64
|
episodeNumbers: [
|
|
61
65
|
{ system: 'xmltv_ns', value: '8.237.0/1' },
|
|
@@ -132,24 +136,26 @@ it('can create new Program', () => {
|
|
|
132
136
|
})
|
|
133
137
|
|
|
134
138
|
it('can create program from exist object', () => {
|
|
135
|
-
const program = new Program(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
const program = new Program(
|
|
140
|
+
{
|
|
141
|
+
titles: [{ value: 'Program 1', lang: 'de' }],
|
|
142
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
143
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
144
|
+
ratings: {
|
|
145
|
+
system: 'MPAA',
|
|
146
|
+
value: 'PG',
|
|
147
|
+
icon: 'http://example.com/pg_symbol.png'
|
|
148
|
+
},
|
|
149
|
+
actors: [{ value: 'Actor1', url: [], image: [] }]
|
|
144
150
|
},
|
|
145
|
-
|
|
146
|
-
|
|
151
|
+
channel
|
|
152
|
+
)
|
|
147
153
|
|
|
148
154
|
expect(program).toMatchObject({
|
|
149
155
|
channel: '1tv',
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
titles: [{ value: 'Program 1', lang: 'de' }],
|
|
157
|
+
sub_titles: [],
|
|
158
|
+
descriptions: [],
|
|
153
159
|
urls: [],
|
|
154
160
|
categories: [],
|
|
155
161
|
icon: {},
|
|
@@ -178,13 +184,15 @@ it('can create program from exist object', () => {
|
|
|
178
184
|
})
|
|
179
185
|
|
|
180
186
|
it('can create program without season number', () => {
|
|
181
|
-
const program = new Program(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
187
|
+
const program = new Program(
|
|
188
|
+
{
|
|
189
|
+
title: 'Program 1',
|
|
190
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
191
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
192
|
+
episode: 238
|
|
193
|
+
},
|
|
194
|
+
channel
|
|
195
|
+
)
|
|
188
196
|
|
|
189
197
|
expect(program.episodeNumbers).toMatchObject([
|
|
190
198
|
{ system: 'xmltv_ns', value: '0.237.0/1' },
|
|
@@ -193,13 +201,16 @@ it('can create program without season number', () => {
|
|
|
193
201
|
})
|
|
194
202
|
|
|
195
203
|
it('can create program without episode number', () => {
|
|
196
|
-
const program = new Program(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
204
|
+
const program = new Program(
|
|
205
|
+
{
|
|
206
|
+
channel: channel.id,
|
|
207
|
+
title: 'Program 1',
|
|
208
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
209
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
210
|
+
season: 3
|
|
211
|
+
},
|
|
212
|
+
channel
|
|
213
|
+
)
|
|
203
214
|
|
|
204
215
|
expect(program.episodeNumbers).toMatchObject([])
|
|
205
216
|
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?><tv date="20220828">
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><url>https://example.com</url></channel>
|
|
4
|
+
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
5
|
+
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
6
|
+
</tv>
|
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
site: 'example.com',
|
|
3
|
+
url: 'https://google.com',
|
|
4
|
+
parser() {
|
|
5
|
+
return [
|
|
6
|
+
{
|
|
7
|
+
title: 'Program1',
|
|
8
|
+
start: 1640995200000,
|
|
9
|
+
stop: 1640998800000
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
title: 'Program1',
|
|
13
|
+
start: 1640995200000,
|
|
14
|
+
stop: 1640998900000
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?><tv date="20220829">
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><url>https://example.com</url></channel>
|
|
4
|
+
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>
|
|
5
|
+
<programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="2TV.com"><title>Program1</title></programme>
|
|
6
|
+
</tv>
|
|
Binary file
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?><tv date="20220829">
|
|
2
|
+
<channel id="1TV.com"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>
|
|
3
|
+
<channel id="2TV.com"><display-name>2 TV</display-name><url>https://example.com</url></channel>
|
|
4
|
+
</tv>
|
|
Binary file
|
package/tests/bin.test.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
const { execSync } = require('child_process')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const epgParser = require('epg-parser')
|
|
2
5
|
|
|
3
6
|
const pwd = `${__dirname}/..`
|
|
4
7
|
|
|
@@ -10,7 +13,7 @@ function stdoutResultTester(stdout) {
|
|
|
10
13
|
|
|
11
14
|
it('can load config', () => {
|
|
12
15
|
const result = execSync(
|
|
13
|
-
`node ${pwd}/bin/epg-grabber.js --config=tests/input/example.config.js --delay=0`,
|
|
16
|
+
`node ${pwd}/bin/epg-grabber.js --config=tests/__data__/input/example.config.js --delay=0`,
|
|
14
17
|
{
|
|
15
18
|
encoding: 'utf8'
|
|
16
19
|
}
|
|
@@ -22,9 +25,9 @@ it('can load config', () => {
|
|
|
22
25
|
it('can load mini config', () => {
|
|
23
26
|
const result = execSync(
|
|
24
27
|
`node ${pwd}/bin/epg-grabber.js \
|
|
25
|
-
--config=tests/input/mini.config.js \
|
|
26
|
-
--channels=tests/input/example.channels.xml \
|
|
27
|
-
--output=tests/output/mini.guide.xml \
|
|
28
|
+
--config=tests/__data__/input/mini.config.js \
|
|
29
|
+
--channels=tests/__data__/input/example.channels.xml \
|
|
30
|
+
--output=tests/__data__/output/mini.guide.xml \
|
|
28
31
|
--lang=fr \
|
|
29
32
|
--days=3 \
|
|
30
33
|
--delay=0 \
|
|
@@ -36,15 +39,17 @@ it('can load mini config', () => {
|
|
|
36
39
|
)
|
|
37
40
|
|
|
38
41
|
expect(stdoutResultTester(result)).toBe(true)
|
|
39
|
-
expect(result.includes("File 'tests/output/mini.guide.xml' successfully saved")).toBe(
|
|
42
|
+
expect(result.includes("File 'tests/__data__/output/mini.guide.xml' successfully saved")).toBe(
|
|
43
|
+
true
|
|
44
|
+
)
|
|
40
45
|
})
|
|
41
46
|
|
|
42
47
|
it('can generate gzip version', () => {
|
|
43
48
|
const result = execSync(
|
|
44
49
|
`node ${pwd}/bin/epg-grabber.js \
|
|
45
|
-
--config=tests/input/mini.config.js \
|
|
46
|
-
--channels=tests/input/example.channels.xml \
|
|
47
|
-
--output=tests/output/mini.guide.xml.gz \
|
|
50
|
+
--config=tests/__data__/input/mini.config.js \
|
|
51
|
+
--channels=tests/__data__/input/example.channels.xml \
|
|
52
|
+
--output=tests/__data__/output/mini.guide.xml.gz \
|
|
48
53
|
--gzip`,
|
|
49
54
|
{
|
|
50
55
|
encoding: 'utf8'
|
|
@@ -52,5 +57,27 @@ it('can generate gzip version', () => {
|
|
|
52
57
|
)
|
|
53
58
|
|
|
54
59
|
expect(stdoutResultTester(result)).toBe(true)
|
|
55
|
-
expect(result.includes("File 'tests/output/mini.guide.xml.gz' successfully saved")).toBe(
|
|
60
|
+
expect(result.includes("File 'tests/__data__/output/mini.guide.xml.gz' successfully saved")).toBe(
|
|
61
|
+
true
|
|
62
|
+
)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('removes duplicates of the program', () => {
|
|
66
|
+
const result = execSync(
|
|
67
|
+
`node ${pwd}/bin/epg-grabber.js \
|
|
68
|
+
--config=tests/__data__/input/duplicates.config.js \
|
|
69
|
+
--channels=tests/__data__/input/example.channels.xml \
|
|
70
|
+
--output=tests/__data__/output/duplicates.guide.xml`,
|
|
71
|
+
{
|
|
72
|
+
encoding: 'utf8'
|
|
73
|
+
}
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
let output = fs.readFileSync(path.resolve(__dirname, '__data__/output/duplicates.guide.xml'))
|
|
77
|
+
let expected = fs.readFileSync(path.resolve(__dirname, '__data__/expected/duplicates.guide.xml'))
|
|
78
|
+
|
|
79
|
+
output = epgParser.parse(output)
|
|
80
|
+
expected = epgParser.parse(expected)
|
|
81
|
+
|
|
82
|
+
expect(output.programs).toEqual(expected.programs)
|
|
56
83
|
})
|
package/tests/config.test.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'path'
|
|
|
3
3
|
import fs from 'fs'
|
|
4
4
|
|
|
5
5
|
it('can load config', () => {
|
|
6
|
-
const config = loadConfig(require(path.resolve('./tests/input/example.config.js')))
|
|
6
|
+
const config = loadConfig(require(path.resolve('./tests/__data__/input/example.config.js')))
|
|
7
7
|
expect(config).toMatchObject({
|
|
8
8
|
days: 1,
|
|
9
9
|
delay: 3000,
|
package/tests/index.test.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @jest-environment node
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { EPGGrabber } from '../src/index'
|
|
5
|
+
import { EPGGrabber, Channel } from '../src/index'
|
|
6
6
|
import axios from 'axios'
|
|
7
7
|
|
|
8
8
|
jest.mock('axios')
|
|
@@ -20,13 +20,13 @@ it('return "Connection timeout" error if server does not response', done => {
|
|
|
20
20
|
},
|
|
21
21
|
parser: () => []
|
|
22
22
|
}
|
|
23
|
-
const channel = {
|
|
23
|
+
const channel = new Channel({
|
|
24
24
|
site: 'example.com',
|
|
25
25
|
site_id: 'cnn',
|
|
26
26
|
xmltv_id: 'CNN.us',
|
|
27
27
|
lang: 'en',
|
|
28
28
|
name: 'CNN'
|
|
29
|
-
}
|
|
29
|
+
})
|
|
30
30
|
const grabber = new EPGGrabber(config)
|
|
31
31
|
grabber.grab(channel, '2022-01-01', (data, err) => {
|
|
32
32
|
expect(err.message).toBe('Connection timeout')
|
|
@@ -47,13 +47,13 @@ it('can grab single channel programs', done => {
|
|
|
47
47
|
url: 'http://example.com/20210319/1tv.json',
|
|
48
48
|
parser: () => []
|
|
49
49
|
}
|
|
50
|
-
const channel = {
|
|
50
|
+
const channel = new Channel({
|
|
51
51
|
site: 'example.com',
|
|
52
52
|
site_id: '1',
|
|
53
53
|
xmltv_id: '1TV.fr',
|
|
54
54
|
lang: 'fr',
|
|
55
55
|
name: '1TV'
|
|
56
|
-
}
|
|
56
|
+
})
|
|
57
57
|
const grabber = new EPGGrabber(config)
|
|
58
58
|
grabber
|
|
59
59
|
.grab(channel, '2022-01-01', (data, err) => {
|
package/tests/parser.test.js
CHANGED
|
@@ -4,7 +4,7 @@ import Program from '../src/Program'
|
|
|
4
4
|
import fs from 'fs'
|
|
5
5
|
|
|
6
6
|
it('can parse valid channels.xml', () => {
|
|
7
|
-
const file = fs.readFileSync('./tests/input/example.channels.xml', { encoding: 'utf-8' })
|
|
7
|
+
const file = fs.readFileSync('./tests/__data__/input/example.channels.xml', { encoding: 'utf-8' })
|
|
8
8
|
const { channels, site } = parseChannels(file)
|
|
9
9
|
|
|
10
10
|
expect(typeof site).toBe('string')
|
|
@@ -14,8 +14,8 @@ it('can parse valid channels.xml', () => {
|
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
it('can parse programs', done => {
|
|
17
|
-
const channel = { xmltv_id: '1tv' }
|
|
18
|
-
const config = require('./input/example.config.js')
|
|
17
|
+
const channel = new Channel({ xmltv_id: '1tv' })
|
|
18
|
+
const config = require('./__data__/input/example.config.js')
|
|
19
19
|
|
|
20
20
|
parsePrograms({ channel, config })
|
|
21
21
|
.then(programs => {
|
|
@@ -27,8 +27,8 @@ it('can parse programs', done => {
|
|
|
27
27
|
})
|
|
28
28
|
|
|
29
29
|
it('can parse programs async', done => {
|
|
30
|
-
const channel = { xmltv_id: '1tv' }
|
|
31
|
-
const config = require('./input/async.config.js')
|
|
30
|
+
const channel = new Channel({ xmltv_id: '1tv' })
|
|
31
|
+
const config = require('./__data__/input/async.config.js')
|
|
32
32
|
|
|
33
33
|
parsePrograms({ channel, config })
|
|
34
34
|
.then(programs => {
|
package/tests/xmltv.test.js
CHANGED
|
@@ -14,11 +14,12 @@ const channels = [
|
|
|
14
14
|
new Channel({
|
|
15
15
|
xmltv_id: '2TV.co',
|
|
16
16
|
name: '2 TV',
|
|
17
|
-
site: 'example.com'
|
|
17
|
+
site: 'example.com',
|
|
18
|
+
lang: 'es'
|
|
18
19
|
})
|
|
19
20
|
]
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
it('can generate xmltv', () => {
|
|
22
23
|
const programs = [
|
|
23
24
|
new Program(
|
|
24
25
|
{
|
|
@@ -33,7 +34,6 @@ fit('can generate xmltv', () => {
|
|
|
33
34
|
season: 9,
|
|
34
35
|
episode: 239,
|
|
35
36
|
icon: 'https://example.com/images/Program1.png?x=шеллы&sid=777',
|
|
36
|
-
channel: '1TV.co',
|
|
37
37
|
rating: {
|
|
38
38
|
system: 'MPAA',
|
|
39
39
|
value: 'PG',
|
|
@@ -60,12 +60,20 @@ fit('can generate xmltv', () => {
|
|
|
60
60
|
writer: 'Writer 1'
|
|
61
61
|
},
|
|
62
62
|
channels[0]
|
|
63
|
+
),
|
|
64
|
+
new Program(
|
|
65
|
+
{
|
|
66
|
+
title: 'Program 2',
|
|
67
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
68
|
+
stop: '2021-03-19T06:30:00.000Z'
|
|
69
|
+
},
|
|
70
|
+
channels[1]
|
|
63
71
|
)
|
|
64
72
|
]
|
|
65
73
|
|
|
66
74
|
const output = xmltv.generate({ channels, programs })
|
|
67
75
|
|
|
68
76
|
expect(output).toBe(
|
|
69
|
-
'<?xml version="1.0" encoding="UTF-8" ?><tv date="20220505">\r\n<channel id="1TV.co"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>\r\n<channel id="2TV.co"><display-name>2 TV</display-name><url>https://example.com</url></channel>\r\n<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><icon src="https://example.com/images/Program1.png?x=шеллы&sid=777"/><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><rating system="MPAA"><value>PG</value><icon src="http://example.com/pg_symbol.png"/></rating></programme>\r\n</tv>'
|
|
77
|
+
'<?xml version="1.0" encoding="UTF-8" ?><tv date="20220505">\r\n<channel id="1TV.co"><display-name>1 TV</display-name><icon src="https://example.com/logos/1TV.png"/><url>https://example.com</url></channel>\r\n<channel id="2TV.co"><display-name>2 TV</display-name><url>https://example.com</url></channel>\r\n<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><icon src="https://example.com/images/Program1.png?x=шеллы&sid=777"/><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><rating system="MPAA"><value>PG</value><icon src="http://example.com/pg_symbol.png"/></rating></programme>\r\n<programme start="20210319060000 +0000" stop="20210319063000 +0000" channel="2TV.co"><title lang="es">Program 2</title></programme>\r\n</tv>'
|
|
70
78
|
)
|
|
71
79
|
})
|