epg-grabber 0.27.2 → 0.28.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/README.md +14 -2
- package/bin/epg-grabber.js +31 -54
- package/package.json +1 -1
- package/src/Channel.js +19 -0
- package/src/Program.js +122 -0
- package/src/client.js +138 -0
- package/src/config.js +34 -0
- package/src/file.js +33 -0
- package/src/index.js +36 -30
- package/src/logger.js +34 -0
- package/src/parser.js +45 -0
- package/src/utils.js +31 -473
- package/src/xmltv.js +124 -0
- package/tests/Channel.test.js +22 -0
- package/tests/Program.test.js +163 -0
- package/tests/bin.test.js +3 -3
- package/tests/client.test.js +47 -0
- package/tests/config.test.js +26 -0
- package/tests/index.test.js +1 -1
- package/tests/input/async.config.js +8 -2
- package/tests/input/{example.com.channels.xml → example.channels.xml} +0 -0
- package/tests/input/{example.com.config.js → example.config.js} +4 -10
- package/tests/parser.test.js +40 -0
- package/tests/utils.test.js +3 -393
- package/tests/xmltv.test.js +71 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import Channel from '../src/Channel'
|
|
2
|
+
import Program from '../src/Program'
|
|
3
|
+
|
|
4
|
+
const channel = new Channel({ xmltv_id: '1tv', lang: 'en' })
|
|
5
|
+
|
|
6
|
+
it('can create new Program', () => {
|
|
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
|
+
]
|
|
48
|
+
},
|
|
49
|
+
channel
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
expect(program).toMatchObject({
|
|
53
|
+
channel: '1tv',
|
|
54
|
+
title: 'Title',
|
|
55
|
+
sub_title: 'Subtitle',
|
|
56
|
+
description: 'Description',
|
|
57
|
+
urls: [{ system: '', value: 'http://example.com/title.html' }],
|
|
58
|
+
categories: ['Category1', 'Category2'],
|
|
59
|
+
icon: { src: 'https://example.com/image.jpg' },
|
|
60
|
+
episodeNumbers: [
|
|
61
|
+
{ system: 'xmltv_ns', value: '8.237.0/1' },
|
|
62
|
+
{ system: 'onscreen', value: 'S09E238' }
|
|
63
|
+
],
|
|
64
|
+
date: 1651795200000,
|
|
65
|
+
start: 1616133600000,
|
|
66
|
+
stop: 1616135400000,
|
|
67
|
+
ratings: [
|
|
68
|
+
{
|
|
69
|
+
system: 'MPAA',
|
|
70
|
+
value: 'PG',
|
|
71
|
+
icon: 'http://example.com/pg_symbol.png'
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
directors: [{ value: 'Director1', url: [], image: [] }],
|
|
75
|
+
actors: [
|
|
76
|
+
{ value: 'Actor1', url: [], image: [] },
|
|
77
|
+
{
|
|
78
|
+
value: 'Actor2',
|
|
79
|
+
url: [{ system: '', value: 'http://actor2.com' }],
|
|
80
|
+
image: [
|
|
81
|
+
{ type: '', size: '', orient: '', system: '', value: 'http://actor2.com/image.png' }
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
writers: [
|
|
86
|
+
{
|
|
87
|
+
value: 'Writer1',
|
|
88
|
+
url: [{ system: 'imdb', value: 'http://imdb.com/p/writer1' }],
|
|
89
|
+
image: [
|
|
90
|
+
{
|
|
91
|
+
value: 'https://example.com/image.jpg',
|
|
92
|
+
type: 'person',
|
|
93
|
+
size: '2',
|
|
94
|
+
system: 'TestSystem',
|
|
95
|
+
orient: 'P'
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
adapters: [
|
|
101
|
+
{
|
|
102
|
+
value: 'Adapter1',
|
|
103
|
+
url: [
|
|
104
|
+
{ system: '', value: 'http://imdb.com/p/adapter1' },
|
|
105
|
+
{ system: '', value: 'http://imdb.com/p/adapter2' }
|
|
106
|
+
],
|
|
107
|
+
image: [
|
|
108
|
+
{
|
|
109
|
+
value: 'https://example.com/image1.jpg',
|
|
110
|
+
type: '',
|
|
111
|
+
size: '',
|
|
112
|
+
system: '',
|
|
113
|
+
orient: ''
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
value: 'https://example.com/image2.jpg',
|
|
117
|
+
type: '',
|
|
118
|
+
size: '',
|
|
119
|
+
system: '',
|
|
120
|
+
orient: ''
|
|
121
|
+
}
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
producers: [],
|
|
126
|
+
composers: [],
|
|
127
|
+
editors: [],
|
|
128
|
+
presenters: [],
|
|
129
|
+
commentators: [],
|
|
130
|
+
guests: []
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
it('can create program without season number', () => {
|
|
135
|
+
const program = new Program(
|
|
136
|
+
{
|
|
137
|
+
title: 'Program 1',
|
|
138
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
139
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
140
|
+
episode: 238
|
|
141
|
+
},
|
|
142
|
+
channel
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
expect(program.episodeNumbers).toMatchObject([
|
|
146
|
+
{ system: 'xmltv_ns', value: '0.237.0/1' },
|
|
147
|
+
{ system: 'onscreen', value: 'S01E238' }
|
|
148
|
+
])
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('can create program without episode number', () => {
|
|
152
|
+
const program = new Program(
|
|
153
|
+
{
|
|
154
|
+
title: 'Program 1',
|
|
155
|
+
start: '2021-03-19T06:00:00.000Z',
|
|
156
|
+
stop: '2021-03-19T06:30:00.000Z',
|
|
157
|
+
season: 3
|
|
158
|
+
},
|
|
159
|
+
channel
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
expect(program.episodeNumbers).toMatchObject([])
|
|
163
|
+
})
|
package/tests/bin.test.js
CHANGED
|
@@ -10,7 +10,7 @@ function stdoutResultTester(stdout) {
|
|
|
10
10
|
|
|
11
11
|
it('can load config', () => {
|
|
12
12
|
const result = execSync(
|
|
13
|
-
`node ${pwd}/bin/epg-grabber.js --config=tests/input/example.
|
|
13
|
+
`node ${pwd}/bin/epg-grabber.js --config=tests/input/example.config.js --delay=0`,
|
|
14
14
|
{
|
|
15
15
|
encoding: 'utf8'
|
|
16
16
|
}
|
|
@@ -23,7 +23,7 @@ it('can load mini config', () => {
|
|
|
23
23
|
const result = execSync(
|
|
24
24
|
`node ${pwd}/bin/epg-grabber.js \
|
|
25
25
|
--config=tests/input/mini.config.js \
|
|
26
|
-
--channels=tests/input/example.
|
|
26
|
+
--channels=tests/input/example.channels.xml \
|
|
27
27
|
--output=tests/output/mini.guide.xml \
|
|
28
28
|
--lang=fr \
|
|
29
29
|
--days=3 \
|
|
@@ -43,7 +43,7 @@ it('can generate gzip version', () => {
|
|
|
43
43
|
const result = execSync(
|
|
44
44
|
`node ${pwd}/bin/epg-grabber.js \
|
|
45
45
|
--config=tests/input/mini.config.js \
|
|
46
|
-
--channels=tests/input/example.
|
|
46
|
+
--channels=tests/input/example.channels.xml \
|
|
47
47
|
--output=tests/output/mini.guide.xml.gz \
|
|
48
48
|
--gzip`,
|
|
49
49
|
{
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { buildRequest, create as createClient } from '../src/client'
|
|
2
|
+
|
|
3
|
+
const config = {
|
|
4
|
+
days: 1,
|
|
5
|
+
lang: 'en',
|
|
6
|
+
delay: 3000,
|
|
7
|
+
output: 'guide.xml',
|
|
8
|
+
request: {
|
|
9
|
+
method: 'POST',
|
|
10
|
+
maxContentLength: 5 * 1024 * 1024,
|
|
11
|
+
timeout: 5000,
|
|
12
|
+
withCredentials: true,
|
|
13
|
+
responseType: 'arraybuffer',
|
|
14
|
+
cache: false,
|
|
15
|
+
data: { accountID: '123' },
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
Cookie: 'abc=123',
|
|
19
|
+
'User-Agent':
|
|
20
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36 Edg/79.0.309.71'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
url: 'http://example.com/20210319/1tv.json'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
it('can build request', done => {
|
|
27
|
+
buildRequest({ config })
|
|
28
|
+
.then(request => {
|
|
29
|
+
expect(request).toMatchObject({
|
|
30
|
+
data: { accountID: '123' },
|
|
31
|
+
headers: {
|
|
32
|
+
'Content-Type': 'application/json',
|
|
33
|
+
Cookie: 'abc=123',
|
|
34
|
+
'User-Agent':
|
|
35
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36 Edg/79.0.309.71'
|
|
36
|
+
},
|
|
37
|
+
maxContentLength: 5242880,
|
|
38
|
+
method: 'POST',
|
|
39
|
+
responseType: 'arraybuffer',
|
|
40
|
+
timeout: 5000,
|
|
41
|
+
url: 'http://example.com/20210319/1tv.json',
|
|
42
|
+
withCredentials: true
|
|
43
|
+
})
|
|
44
|
+
done()
|
|
45
|
+
})
|
|
46
|
+
.catch(done)
|
|
47
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { load as loadConfig } from '../src/config'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
|
|
5
|
+
it('can load config', () => {
|
|
6
|
+
const config = loadConfig(require(path.resolve('./tests/input/example.config.js')))
|
|
7
|
+
expect(config).toMatchObject({
|
|
8
|
+
days: 1,
|
|
9
|
+
delay: 3000,
|
|
10
|
+
lang: 'en',
|
|
11
|
+
site: 'example.com'
|
|
12
|
+
})
|
|
13
|
+
expect(config.request).toMatchObject({
|
|
14
|
+
timeout: 5000,
|
|
15
|
+
headers: {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
Cookie: 'abc=123'
|
|
18
|
+
}
|
|
19
|
+
})
|
|
20
|
+
expect(typeof config.request.data).toEqual('function')
|
|
21
|
+
expect(typeof config.url).toEqual('function')
|
|
22
|
+
expect(typeof config.logo).toEqual('function')
|
|
23
|
+
expect(config.request.data()).toEqual({ accountID: '123' })
|
|
24
|
+
expect(config.url()).toEqual('http://example.com/20210319/1tv.json')
|
|
25
|
+
expect(config.logo()).toEqual('http://example.com/logos/1TV.png?x=шеллы&sid=777')
|
|
26
|
+
})
|
package/tests/index.test.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module.exports = {
|
|
2
2
|
site: 'example.com',
|
|
3
|
-
channels: 'example.
|
|
3
|
+
channels: 'example.channels.xml',
|
|
4
4
|
url() {
|
|
5
5
|
return Promise.resolve('http://example.com/20210319/1tv.json')
|
|
6
6
|
},
|
|
@@ -17,7 +17,13 @@ module.exports = {
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
parser() {
|
|
20
|
-
return Promise.resolve([
|
|
20
|
+
return Promise.resolve([
|
|
21
|
+
{
|
|
22
|
+
title: 'Program1',
|
|
23
|
+
start: 1640995200000,
|
|
24
|
+
stop: 1640998800000
|
|
25
|
+
}
|
|
26
|
+
])
|
|
21
27
|
},
|
|
22
28
|
logo() {
|
|
23
29
|
return Promise.resolve('http://example.com/logos/1TV.png?x=шеллы&sid=777')
|
|
File without changes
|
|
@@ -5,7 +5,7 @@ dayjs.extend(utc)
|
|
|
5
5
|
|
|
6
6
|
module.exports = {
|
|
7
7
|
site: 'example.com',
|
|
8
|
-
channels: 'example.
|
|
8
|
+
channels: 'example.channels.xml',
|
|
9
9
|
output: 'tests/output/guide.xml',
|
|
10
10
|
url: () => 'http://example.com/20210319/1tv.json',
|
|
11
11
|
request: {
|
|
@@ -21,15 +21,9 @@ module.exports = {
|
|
|
21
21
|
parser: () => {
|
|
22
22
|
return [
|
|
23
23
|
{
|
|
24
|
-
title: '
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
category: ['Category1', 'Category2'],
|
|
28
|
-
icon: 'https://example.com/image.jpg',
|
|
29
|
-
season: 9,
|
|
30
|
-
episode: 238,
|
|
31
|
-
start: dayjs.utc('2022-01-01 00:00:00'),
|
|
32
|
-
stop: dayjs.utc('2022-01-01 01:00:00')
|
|
24
|
+
title: 'Program1',
|
|
25
|
+
start: 1640995200000,
|
|
26
|
+
stop: 1640998800000
|
|
33
27
|
}
|
|
34
28
|
]
|
|
35
29
|
},
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { parseChannels, parsePrograms } from '../src/parser'
|
|
2
|
+
import Channel from '../src/Channel'
|
|
3
|
+
import Program from '../src/Program'
|
|
4
|
+
import fs from 'fs'
|
|
5
|
+
|
|
6
|
+
it('can parse valid channels.xml', () => {
|
|
7
|
+
const file = fs.readFileSync('./tests/input/example.channels.xml', { encoding: 'utf-8' })
|
|
8
|
+
const { channels, site } = parseChannels(file)
|
|
9
|
+
|
|
10
|
+
expect(typeof site).toBe('string')
|
|
11
|
+
expect(channels.length).toBe(2)
|
|
12
|
+
expect(channels[0]).toBeInstanceOf(Channel)
|
|
13
|
+
expect(channels[1]).toBeInstanceOf(Channel)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
it('can parse programs', done => {
|
|
17
|
+
const channel = { xmltv_id: '1tv' }
|
|
18
|
+
const config = require('./input/example.config.js')
|
|
19
|
+
|
|
20
|
+
parsePrograms({ channel, config })
|
|
21
|
+
.then(programs => {
|
|
22
|
+
expect(programs.length).toBe(1)
|
|
23
|
+
expect(programs[0]).toBeInstanceOf(Program)
|
|
24
|
+
done()
|
|
25
|
+
})
|
|
26
|
+
.catch(done)
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('can parse programs async', done => {
|
|
30
|
+
const channel = { xmltv_id: '1tv' }
|
|
31
|
+
const config = require('./input/async.config.js')
|
|
32
|
+
|
|
33
|
+
parsePrograms({ channel, config })
|
|
34
|
+
.then(programs => {
|
|
35
|
+
expect(programs.length).toBe(1)
|
|
36
|
+
expect(programs[0]).toBeInstanceOf(Program)
|
|
37
|
+
done()
|
|
38
|
+
})
|
|
39
|
+
.catch(done)
|
|
40
|
+
})
|