epg-grabber 0.17.0 → 0.20.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/README.md +0 -1
- package/bin/epg-grabber.js +20 -16
- package/package.json +1 -1
- package/src/index.js +17 -29
- package/src/utils.js +6 -2
- package/tests/index.test.js +2 -22
- package/tests/input/example.com.config.js +20 -2
- package/tests/input/mini.config.js +0 -1
- package/tests/utils.test.js +25 -4
package/README.md
CHANGED
|
@@ -94,7 +94,6 @@ module.exports = {
|
|
|
94
94
|
lang: 'fr', // default language for all programs (default: 'en')
|
|
95
95
|
days: 3, // number of days for which to grab the program (default: 1)
|
|
96
96
|
delay: 5000, // delay between requests (default: 3000)
|
|
97
|
-
ignore: true, // skip all channels during request (default: false)
|
|
98
97
|
|
|
99
98
|
request: { // request options (details: https://github.com/axios/axios#request-config)
|
|
100
99
|
|
package/bin/epg-grabber.js
CHANGED
|
@@ -79,28 +79,32 @@ async function main() {
|
|
|
79
79
|
if (!config.channels) return logger.error('Path to [site].channels.xml is missing')
|
|
80
80
|
logger.info(`Loading '${config.channels}'...`)
|
|
81
81
|
const channelsXML = fs.readFileSync(path.resolve(config.channels), { encoding: 'utf-8' })
|
|
82
|
-
const channels = utils.parseChannels(channelsXML)
|
|
82
|
+
const { channels } = utils.parseChannels(channelsXML)
|
|
83
83
|
|
|
84
84
|
let programs = []
|
|
85
85
|
let i = 1
|
|
86
86
|
let days = options.days || 1
|
|
87
87
|
const total = channels.length * days
|
|
88
|
+
const utcDate = utils.getUTCDate()
|
|
89
|
+
const dates = Array.from({ length: config.days }, (_, i) => utcDate.add(i, 'd'))
|
|
88
90
|
for (let channel of channels) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
for (let date of dates) {
|
|
92
|
+
await grabber
|
|
93
|
+
.grab(channel, date, config, (data, err) => {
|
|
94
|
+
logger.info(
|
|
95
|
+
`[${i}/${total}] ${config.site} - ${data.channel.xmltv_id} - ${data.date.format(
|
|
96
|
+
'MMM D, YYYY'
|
|
97
|
+
)} (${data.programs.length} programs)`
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if (err) logger.error(err.message)
|
|
101
|
+
|
|
102
|
+
if (i < total) i++
|
|
103
|
+
})
|
|
104
|
+
.then(results => {
|
|
105
|
+
programs = programs.concat(results)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
104
108
|
}
|
|
105
109
|
|
|
106
110
|
const xml = utils.convertToXMLTV({ config, channels, programs })
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,41 +1,29 @@
|
|
|
1
1
|
const utils = require('./utils')
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
grab: async function (channel, config, cb) {
|
|
4
|
+
grab: async function (channel, date, config, cb) {
|
|
5
|
+
date = typeof date === 'string' ? utils.getUTCDate(date) : date
|
|
5
6
|
config = utils.loadConfig(config)
|
|
6
7
|
channel.lang = channel.lang || config.lang || null
|
|
7
8
|
|
|
8
|
-
const utcDate = utils.getUTCDate()
|
|
9
|
-
const dates = Array.from({ length: config.days }, (_, i) => utcDate.add(i, 'd'))
|
|
10
|
-
const queue = []
|
|
11
|
-
dates.forEach(date => {
|
|
12
|
-
queue.push({ date, channel })
|
|
13
|
-
})
|
|
14
|
-
|
|
15
9
|
let programs = []
|
|
16
|
-
for (let item of queue) {
|
|
17
|
-
if (config.ignore) {
|
|
18
|
-
item.programs = []
|
|
19
|
-
cb(item, new Error('Skipped'))
|
|
20
|
-
continue
|
|
21
|
-
}
|
|
22
10
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
11
|
+
const item = { date, channel }
|
|
12
|
+
await utils
|
|
13
|
+
.buildRequest(item, config)
|
|
14
|
+
.then(request => utils.fetchData(request))
|
|
15
|
+
.then(response => utils.parseResponse(item, response, config))
|
|
16
|
+
.then(results => {
|
|
17
|
+
item.programs = results
|
|
18
|
+
cb(item, null)
|
|
19
|
+
programs = programs.concat(results)
|
|
20
|
+
})
|
|
21
|
+
.catch(err => {
|
|
22
|
+
item.programs = []
|
|
23
|
+
cb(item, err)
|
|
24
|
+
})
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
}
|
|
26
|
+
await utils.sleep(config.delay)
|
|
39
27
|
|
|
40
28
|
return programs
|
|
41
29
|
},
|
package/src/utils.js
CHANGED
|
@@ -65,7 +65,7 @@ utils.parseChannels = function (xml) {
|
|
|
65
65
|
return channel
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
return channels
|
|
68
|
+
return { site, channels }
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
utils.sleep = function (ms) {
|
|
@@ -259,7 +259,9 @@ utils.getRequestUrl = async function (item, config) {
|
|
|
259
259
|
return config.url
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
-
utils.getUTCDate = function () {
|
|
262
|
+
utils.getUTCDate = function (d = null) {
|
|
263
|
+
if (typeof d === 'string') return dayjs.utc(d).startOf('d')
|
|
264
|
+
|
|
263
265
|
return dayjs.utc().startOf('d')
|
|
264
266
|
}
|
|
265
267
|
|
|
@@ -295,6 +297,8 @@ utils.parsePrograms = async function (data, config) {
|
|
|
295
297
|
title: program.title,
|
|
296
298
|
description: program.description || null,
|
|
297
299
|
category: program.category || null,
|
|
300
|
+
season: program.season || null,
|
|
301
|
+
episode: program.episode || null,
|
|
298
302
|
icon: program.icon || null,
|
|
299
303
|
channel: channel.xmltv_id,
|
|
300
304
|
lang: program.lang || channel.lang || config.lang || 'en',
|
package/tests/index.test.js
CHANGED
|
@@ -27,7 +27,7 @@ it('return "Connection timeout" error if server does not response', done => {
|
|
|
27
27
|
lang: 'en',
|
|
28
28
|
name: 'CNN'
|
|
29
29
|
}
|
|
30
|
-
grabber.grab(channel, config, (data, err) => {
|
|
30
|
+
grabber.grab(channel, '2022-01-01', config, (data, err) => {
|
|
31
31
|
expect(err.message).toBe('Connection timeout')
|
|
32
32
|
done()
|
|
33
33
|
})
|
|
@@ -54,7 +54,7 @@ it('can grab single channel programs', done => {
|
|
|
54
54
|
name: '1TV'
|
|
55
55
|
}
|
|
56
56
|
grabber
|
|
57
|
-
.grab(channel, config, (data, err) => {
|
|
57
|
+
.grab(channel, '2022-01-01', config, (data, err) => {
|
|
58
58
|
if (err) {
|
|
59
59
|
console.log(` Error: ${err.message}`)
|
|
60
60
|
done()
|
|
@@ -71,23 +71,3 @@ it('can grab single channel programs', done => {
|
|
|
71
71
|
done()
|
|
72
72
|
})
|
|
73
73
|
})
|
|
74
|
-
|
|
75
|
-
it('return "Skipped" error if ignore option in config is true', done => {
|
|
76
|
-
const config = {
|
|
77
|
-
site: 'example.com',
|
|
78
|
-
ignore: true,
|
|
79
|
-
url: `http://example.com/20210319/1tv.json`,
|
|
80
|
-
parser: () => []
|
|
81
|
-
}
|
|
82
|
-
const channel = {
|
|
83
|
-
site: 'example.com',
|
|
84
|
-
site_id: 'cnn',
|
|
85
|
-
xmltv_id: 'CNN.us',
|
|
86
|
-
lang: 'en',
|
|
87
|
-
name: 'CNN'
|
|
88
|
-
}
|
|
89
|
-
grabber.grab(channel, config, (data, err) => {
|
|
90
|
-
expect(err.message).toBe('Skipped')
|
|
91
|
-
done()
|
|
92
|
-
})
|
|
93
|
-
})
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
const dayjs = require('dayjs')
|
|
2
|
+
const utc = require('dayjs/plugin/utc')
|
|
3
|
+
|
|
4
|
+
dayjs.extend(utc)
|
|
5
|
+
|
|
1
6
|
module.exports = {
|
|
2
7
|
site: 'example.com',
|
|
3
|
-
ignore: true,
|
|
4
8
|
channels: 'example.com.channels.xml',
|
|
5
9
|
output: 'tests/output/guide.xml',
|
|
6
10
|
url: () => 'http://example.com/20210319/1tv.json',
|
|
@@ -14,6 +18,20 @@ module.exports = {
|
|
|
14
18
|
return { accountID: '123' }
|
|
15
19
|
}
|
|
16
20
|
},
|
|
17
|
-
parser: () =>
|
|
21
|
+
parser: () => {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
title: 'Title',
|
|
25
|
+
description: 'Description',
|
|
26
|
+
lang: 'en',
|
|
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')
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
18
36
|
logo: () => 'http://example.com/logos/1TV.png?x=шеллы&sid=777'
|
|
19
37
|
}
|
package/tests/utils.test.js
CHANGED
|
@@ -7,7 +7,6 @@ it('can load valid config.js', () => {
|
|
|
7
7
|
const config = utils.loadConfig(require(path.resolve('./tests/input/example.com.config.js')))
|
|
8
8
|
expect(config).toMatchObject({
|
|
9
9
|
days: 1,
|
|
10
|
-
ignore: true,
|
|
11
10
|
delay: 3000,
|
|
12
11
|
lang: 'en',
|
|
13
12
|
site: 'example.com'
|
|
@@ -29,7 +28,7 @@ it('can load valid config.js', () => {
|
|
|
29
28
|
|
|
30
29
|
it('can parse valid channels.xml', () => {
|
|
31
30
|
const file = fs.readFileSync('./tests/input/example.com.channels.xml', { encoding: 'utf-8' })
|
|
32
|
-
const channels = utils.parseChannels(file)
|
|
31
|
+
const { channels } = utils.parseChannels(file)
|
|
33
32
|
expect(channels).toEqual([
|
|
34
33
|
{
|
|
35
34
|
name: '1 TV',
|
|
@@ -52,7 +51,7 @@ it('can parse valid channels.xml', () => {
|
|
|
52
51
|
|
|
53
52
|
it('can convert object to xmltv string', () => {
|
|
54
53
|
const file = fs.readFileSync('./tests/input/example.com.channels.xml', { encoding: 'utf-8' })
|
|
55
|
-
const channels = utils.parseChannels(file)
|
|
54
|
+
const { channels } = utils.parseChannels(file)
|
|
56
55
|
const programs = [
|
|
57
56
|
{
|
|
58
57
|
title: 'Program 1',
|
|
@@ -102,7 +101,7 @@ it('can convert object to xmltv string without categories', () => {
|
|
|
102
101
|
|
|
103
102
|
it('can convert object to xmltv string with multiple categories', () => {
|
|
104
103
|
const file = fs.readFileSync('./tests/input/example.com.channels.xml', { encoding: 'utf-8' })
|
|
105
|
-
const channels = utils.parseChannels(file)
|
|
104
|
+
const { channels } = utils.parseChannels(file)
|
|
106
105
|
const programs = [
|
|
107
106
|
{
|
|
108
107
|
title: 'Program 1',
|
|
@@ -198,6 +197,28 @@ it('can load logo async', done => {
|
|
|
198
197
|
})
|
|
199
198
|
})
|
|
200
199
|
|
|
200
|
+
it('can parse programs', done => {
|
|
201
|
+
const config = utils.loadConfig(require(path.resolve('./tests/input/example.com.config.js')))
|
|
202
|
+
return utils
|
|
203
|
+
.parsePrograms({ channel: { xmltv_id: '1tv', lang: 'en' } }, config)
|
|
204
|
+
.then(programs => {
|
|
205
|
+
expect(programs).toMatchObject([
|
|
206
|
+
{
|
|
207
|
+
title: 'Title',
|
|
208
|
+
description: 'Description',
|
|
209
|
+
lang: 'en',
|
|
210
|
+
category: ['Category1', 'Category2'],
|
|
211
|
+
icon: 'https://example.com/image.jpg',
|
|
212
|
+
season: 9,
|
|
213
|
+
episode: 238,
|
|
214
|
+
start: 1640995200,
|
|
215
|
+
stop: 1640998800
|
|
216
|
+
}
|
|
217
|
+
])
|
|
218
|
+
done()
|
|
219
|
+
})
|
|
220
|
+
})
|
|
221
|
+
|
|
201
222
|
it('can parse programs async', done => {
|
|
202
223
|
const config = utils.loadConfig(require(path.resolve('./tests/input/async.config.js')))
|
|
203
224
|
return utils
|