epg-grabber 0.35.0 → 0.36.1
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/package.json +1 -1
- package/src/client.js +14 -12
- package/src/config.js +27 -27
- package/src/index.js +22 -10
- package/tests/__data__/output/guide.xml +1 -1
- package/tests/config.test.js +2 -2
- package/tests/index.test.js +51 -9
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -14,18 +14,20 @@ module.exports.parseResponse = parseResponse
|
|
|
14
14
|
let timeout
|
|
15
15
|
|
|
16
16
|
function create(config) {
|
|
17
|
-
const client =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
17
|
+
const client = axios.defaults.cache
|
|
18
|
+
? axios
|
|
19
|
+
: setupCookie(
|
|
20
|
+
setupCache(
|
|
21
|
+
axios.create({
|
|
22
|
+
jar,
|
|
23
|
+
ignoreCookieErrors: true,
|
|
24
|
+
headers: {
|
|
25
|
+
'User-Agent':
|
|
26
|
+
'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'
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
)
|
|
30
|
+
)
|
|
29
31
|
|
|
30
32
|
client.interceptors.request.use(
|
|
31
33
|
function (request) {
|
package/src/config.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
const tough = require('tough-cookie')
|
|
2
2
|
const { merge } = require('lodash')
|
|
3
3
|
|
|
4
|
-
module.exports.
|
|
4
|
+
module.exports.parse = parse
|
|
5
5
|
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
6
|
+
function parse(config) {
|
|
7
|
+
if (!config.site) throw new Error("The required 'site' property is missing")
|
|
8
|
+
if (!config.url) throw new Error("The required 'url' property is missing")
|
|
9
|
+
if (typeof config.url !== 'function' && typeof config.url !== 'string')
|
|
10
|
+
throw new Error("The 'url' property should return the function or string")
|
|
11
|
+
if (!config.parser) throw new Error("The required 'parser' function is missing")
|
|
12
|
+
if (typeof config.parser !== 'function')
|
|
13
|
+
throw new Error("The 'parser' property should return the function")
|
|
14
|
+
if (config.logo && typeof config.logo !== 'function')
|
|
15
|
+
throw new Error("The 'logo' property should return the function")
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
17
|
+
const defaultConfig = {
|
|
18
|
+
days: 1,
|
|
19
|
+
lang: 'en',
|
|
20
|
+
delay: 3000,
|
|
21
|
+
output: 'guide.xml',
|
|
22
|
+
request: {
|
|
23
|
+
method: 'GET',
|
|
24
|
+
maxContentLength: 5 * 1024 * 1024,
|
|
25
|
+
timeout: 5000,
|
|
26
|
+
withCredentials: true,
|
|
27
|
+
jar: new tough.CookieJar(),
|
|
28
|
+
responseType: 'arraybuffer',
|
|
29
|
+
cache: false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
return merge(defaultConfig, config)
|
|
34
34
|
}
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ const { create: createClient, buildRequest, parseResponse } = require('./client'
|
|
|
3
3
|
const { parseChannels, parsePrograms } = require('./parser')
|
|
4
4
|
const { sleep, isPromise, getUTCDate } = require('./utils')
|
|
5
5
|
const { generate: generateXMLTV } = require('./xmltv')
|
|
6
|
-
const {
|
|
6
|
+
const { parse: parseConfig } = require('./config')
|
|
7
7
|
const Channel = require('./Channel')
|
|
8
8
|
const Program = require('./Program')
|
|
9
9
|
|
|
@@ -14,7 +14,7 @@ module.exports.Program = Program
|
|
|
14
14
|
|
|
15
15
|
class EPGGrabber {
|
|
16
16
|
constructor(config = {}) {
|
|
17
|
-
this.config =
|
|
17
|
+
this.config = config
|
|
18
18
|
this.client = createClient(config)
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -26,18 +26,24 @@ class EPGGrabber {
|
|
|
26
26
|
return logo
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
async grab(channel, date, cb = () => {}) {
|
|
29
|
+
async grab(channel, date, config = {}, cb = () => {}) {
|
|
30
|
+
if (typeof config == 'function') {
|
|
31
|
+
cb = config
|
|
32
|
+
config = {}
|
|
33
|
+
}
|
|
34
|
+
config = merge(this.config, config)
|
|
35
|
+
config = parseConfig(config)
|
|
30
36
|
if (!(channel instanceof Channel)) {
|
|
31
37
|
throw new Error('The first argument must be the "Channel" class')
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
await sleep(
|
|
40
|
+
await sleep(config.delay)
|
|
35
41
|
|
|
36
42
|
date = typeof date === 'string' ? getUTCDate(date) : date
|
|
37
|
-
return buildRequest({ channel, date, config
|
|
43
|
+
return buildRequest({ channel, date, config })
|
|
38
44
|
.then(this.client)
|
|
39
45
|
.then(parseResponse)
|
|
40
|
-
.then(data => merge({ channel, date, config
|
|
46
|
+
.then(data => merge({ channel, date, config }, data))
|
|
41
47
|
.then(parsePrograms)
|
|
42
48
|
.then(programs => {
|
|
43
49
|
cb({ channel, date, programs })
|
|
@@ -45,7 +51,7 @@ class EPGGrabber {
|
|
|
45
51
|
return programs
|
|
46
52
|
})
|
|
47
53
|
.catch(err => {
|
|
48
|
-
if (
|
|
54
|
+
if (config.debug) console.log('Error:', JSON.stringify(err, null, 2))
|
|
49
55
|
cb({ channel, date, programs: [] }, err)
|
|
50
56
|
|
|
51
57
|
return []
|
|
@@ -58,12 +64,18 @@ class EPGGrabberMock {
|
|
|
58
64
|
this.config = config
|
|
59
65
|
}
|
|
60
66
|
|
|
61
|
-
async grab(channel, date, cb) {
|
|
67
|
+
async grab(channel, date, config = {}, cb = () => {}) {
|
|
62
68
|
let _date = getUTCDate(date)
|
|
63
|
-
|
|
69
|
+
if (typeof config == 'function') {
|
|
70
|
+
cb = config
|
|
71
|
+
config = {}
|
|
72
|
+
}
|
|
73
|
+
config = merge(this.config, config)
|
|
74
|
+
config = parseConfig(config)
|
|
75
|
+
let _programs = await config.parser({ channel, date: _date })
|
|
64
76
|
let programs = _programs.map(data => new Program(data, channel))
|
|
65
77
|
|
|
66
|
-
if (
|
|
78
|
+
if (config.request?.timeout !== undefined && config.request.timeout < 1) {
|
|
67
79
|
cb({ programs: [], date: _date, channel }, new Error('Connection timeout'))
|
|
68
80
|
return []
|
|
69
81
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8" ?><tv date="
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" ?><tv date="20231201">
|
|
2
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
3
|
<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>
|
|
4
4
|
<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>
|
package/tests/config.test.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parse as parseConfig } from '../src/config'
|
|
2
2
|
import path from 'path'
|
|
3
3
|
import fs from 'fs'
|
|
4
4
|
|
|
5
5
|
it('can load config', () => {
|
|
6
|
-
const config =
|
|
6
|
+
const config = parseConfig(require(path.resolve('./tests/__data__/input/example.config.js')))
|
|
7
7
|
expect(config).toMatchObject({
|
|
8
8
|
days: 2,
|
|
9
9
|
delay: 3000,
|
package/tests/index.test.js
CHANGED
|
@@ -28,16 +28,18 @@ it('return "Connection timeout" error if server does not response', done => {
|
|
|
28
28
|
name: 'CNN'
|
|
29
29
|
})
|
|
30
30
|
const grabber = new EPGGrabber(config)
|
|
31
|
-
grabber
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
grabber
|
|
32
|
+
.grab(channel, '2022-01-01', (data, err) => {
|
|
33
|
+
expect(err.message).toBe('Connection timeout')
|
|
34
|
+
done()
|
|
35
|
+
})
|
|
36
|
+
.catch(done)
|
|
35
37
|
})
|
|
36
38
|
|
|
37
39
|
it('can grab single channel programs', done => {
|
|
38
40
|
const data = {
|
|
39
41
|
data: {
|
|
40
|
-
toString: () => '
|
|
42
|
+
toString: () => '[{"title":"Program1"}]'
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
axios.mockImplementation(() => Promise.resolve(data))
|
|
@@ -45,7 +47,7 @@ it('can grab single channel programs', done => {
|
|
|
45
47
|
const config = {
|
|
46
48
|
site: 'example.com',
|
|
47
49
|
url: 'http://example.com/20210319/1tv.json',
|
|
48
|
-
parser: () =>
|
|
50
|
+
parser: ({ content }) => JSON.parse(content)
|
|
49
51
|
}
|
|
50
52
|
const channel = new Channel({
|
|
51
53
|
site: 'example.com',
|
|
@@ -56,13 +58,53 @@ it('can grab single channel programs', done => {
|
|
|
56
58
|
})
|
|
57
59
|
const grabber = new EPGGrabber(config)
|
|
58
60
|
grabber
|
|
59
|
-
.grab(channel, '2022-01-01'
|
|
61
|
+
.grab(channel, '2022-01-01')
|
|
62
|
+
.then(programs => {
|
|
63
|
+
expect(programs[0].titles).toMatchObject([
|
|
64
|
+
{
|
|
65
|
+
lang: 'fr',
|
|
66
|
+
value: 'Program1'
|
|
67
|
+
}
|
|
68
|
+
])
|
|
69
|
+
done()
|
|
70
|
+
})
|
|
71
|
+
.catch(done)
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('can use a different config for different requests', done => {
|
|
75
|
+
const data = {
|
|
76
|
+
data: {
|
|
77
|
+
toString: () => '[{"title":"Program1"}]'
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
axios.mockImplementation(() => Promise.resolve(data))
|
|
81
|
+
|
|
82
|
+
const config = {
|
|
83
|
+
site: 'example.com',
|
|
84
|
+
url: 'http://example.com/20210319/1tv.json',
|
|
85
|
+
parser: ({ content }) => JSON.parse(content)
|
|
86
|
+
}
|
|
87
|
+
const channel = new Channel({
|
|
88
|
+
site: 'example.com',
|
|
89
|
+
site_id: '1',
|
|
90
|
+
xmltv_id: '1TV.fr',
|
|
91
|
+
lang: 'fr',
|
|
92
|
+
name: '1TV'
|
|
93
|
+
})
|
|
94
|
+
const grabber = new EPGGrabber()
|
|
95
|
+
grabber
|
|
96
|
+
.grab(channel, '2022-01-01', config, (data, err) => {
|
|
60
97
|
if (err) {
|
|
61
|
-
done()
|
|
98
|
+
done(err)
|
|
62
99
|
}
|
|
63
100
|
})
|
|
64
101
|
.then(programs => {
|
|
65
|
-
expect(programs.
|
|
102
|
+
expect(programs[0].titles).toMatchObject([
|
|
103
|
+
{
|
|
104
|
+
lang: 'fr',
|
|
105
|
+
value: 'Program1'
|
|
106
|
+
}
|
|
107
|
+
])
|
|
66
108
|
done()
|
|
67
109
|
})
|
|
68
110
|
})
|