epg-grabber 0.24.0 → 0.25.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 CHANGED
@@ -80,7 +80,8 @@ Arguments:
80
80
  - `--days`: number of days for which to grab the program (default: 1)
81
81
  - `--delay`: delay between requests (default: 3000)
82
82
  - `--timeout`: set a timeout for each request (default: 5000)
83
- - `--gzip`: compress output (default: false)
83
+ - `--cache-max-age`: maximum time for storing each request in milliseconds (default: 0)
84
+ - `--gzip`: compress the output (default: false)
84
85
  - `--debug`: enable debug mode (default: false)
85
86
  - `--curl`: display current request as CURL (default: false)
86
87
  - `--log`: path to log file (optional)
@@ -101,6 +102,13 @@ module.exports = {
101
102
 
102
103
  method: 'GET',
103
104
  timeout: 5000,
105
+ cache: { // cache options (details: https://github.com/RasCarlito/axios-cache-adapter#options)
106
+ maxAge: 0,
107
+ readHeaders: false,
108
+ exclude: {
109
+ query: false
110
+ }
111
+ },
104
112
 
105
113
  /**
106
114
  * @param {object} context
@@ -4,7 +4,7 @@ const { Command } = require('commander')
4
4
  const program = new Command()
5
5
  const fs = require('fs')
6
6
  const path = require('path')
7
- const grabber = require('../src/index')
7
+ const EPGGrabber = require('../src/index')
8
8
  const utils = require('../src/utils')
9
9
  const { name, version, description } = require('../package.json')
10
10
  const { merge } = require('lodash')
@@ -23,6 +23,11 @@ program
23
23
  .option('--days <days>', 'Number of days for which to grab the program', parseInteger, 1)
24
24
  .option('--delay <delay>', 'Delay between requests (in mileseconds)', parseInteger)
25
25
  .option('--timeout <timeout>', 'Set a timeout for each request (in mileseconds)', parseInteger)
26
+ .option(
27
+ '--cache-max-age <cacheMaxAge>',
28
+ 'Maximum time for storing each request (in milliseconds)',
29
+ parseInteger
30
+ )
26
31
  .option('--gzip', 'Compress the output', false)
27
32
  .option('--debug', 'Enable debug mode', false)
28
33
  .option('--curl', 'Display request as CURL', false)
@@ -72,7 +77,10 @@ async function main() {
72
77
  lang: options.lang,
73
78
  delay: options.delay,
74
79
  request: {
75
- timeout: options.timeout
80
+ timeout: options.timeout,
81
+ cache: {
82
+ maxAge: options.cacheMaxAge
83
+ }
76
84
  }
77
85
  })
78
86
 
@@ -92,10 +100,11 @@ async function main() {
92
100
  const total = channels.length * days
93
101
  const utcDate = utils.getUTCDate()
94
102
  const dates = Array.from({ length: config.days }, (_, i) => utcDate.add(i, 'd'))
103
+ const grabber = new EPGGrabber(config)
95
104
  for (let channel of channels) {
96
105
  for (let date of dates) {
97
106
  await grabber
98
- .grab(channel, date, config, (data, err) => {
107
+ .grab(channel, date, (data, err) => {
99
108
  logger.info(
100
109
  `[${i}/${total}] ${config.site} - ${data.channel.xmltv_id} - ${data.date.format(
101
110
  'MMM D, YYYY'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epg-grabber",
3
- "version": "0.24.0",
3
+ "version": "0.25.2",
4
4
  "description": "Node.js CLI tool for grabbing EPG from different sites",
5
5
  "main": "src/index.js",
6
6
  "preferGlobal": true,
@@ -29,6 +29,7 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "axios": "^0.21.1",
32
+ "axios-cache-adapter": "^2.7.3",
32
33
  "axios-cookiejar-support": "^1.0.1",
33
34
  "axios-mock-adapter": "^1.20.0",
34
35
  "commander": "^7.1.0",
package/src/index.js CHANGED
@@ -1,18 +1,21 @@
1
1
  const utils = require('./utils')
2
2
 
3
- module.exports = {
4
- grab: async function (channel, date, config, cb) {
3
+ class EPGGrabber {
4
+ constructor(config = {}) {
5
+ this.config = utils.loadConfig(config)
6
+ this.client = utils.createClient(config)
7
+ }
8
+
9
+ async grab(channel, date, cb = () => {}) {
5
10
  date = typeof date === 'string' ? utils.getUTCDate(date) : date
6
- config = utils.loadConfig(config)
7
- channel.lang = channel.lang || config.lang || null
11
+ channel.lang = channel.lang || this.config.lang || null
8
12
 
9
13
  let programs = []
10
-
11
14
  const item = { date, channel }
12
15
  await utils
13
- .buildRequest(item, config)
14
- .then(request => utils.fetchData(request))
15
- .then(response => utils.parseResponse(item, response, config))
16
+ .buildRequest(item, this.config)
17
+ .then(request => utils.fetchData(this.client, request))
18
+ .then(response => utils.parseResponse(item, response, this.config))
16
19
  .then(results => {
17
20
  item.programs = results
18
21
  cb(item, null)
@@ -20,16 +23,19 @@ module.exports = {
20
23
  })
21
24
  .catch(error => {
22
25
  item.programs = []
23
- if (config.debug) {
26
+ if (this.config.debug) {
24
27
  console.log('Error:', JSON.stringify(error, null, 2))
25
28
  }
26
29
  cb(item, error)
27
30
  })
28
31
 
29
- await utils.sleep(config.delay)
32
+ await utils.sleep(this.config.delay)
30
33
 
31
34
  return programs
32
- },
33
- convertToXMLTV: utils.convertToXMLTV,
34
- parseChannels: utils.parseChannels
35
+ }
35
36
  }
37
+
38
+ EPGGrabber.convertToXMLTV = utils.convertToXMLTV
39
+ EPGGrabber.parseChannels = utils.parseChannels
40
+
41
+ module.exports = EPGGrabber
package/src/utils.js CHANGED
@@ -3,6 +3,7 @@ const { padStart } = require('lodash')
3
3
  const path = require('path')
4
4
  const axios = require('axios').default
5
5
  const axiosCookieJarSupport = require('axios-cookiejar-support').default
6
+ const axiosCacheAdapter = require('axios-cache-adapter')
6
7
  const tough = require('tough-cookie')
7
8
  const convert = require('xml-js')
8
9
  const { merge } = require('lodash')
@@ -39,13 +40,66 @@ utils.loadConfig = function (config) {
39
40
  timeout: 5000,
40
41
  withCredentials: true,
41
42
  jar: new tough.CookieJar(),
42
- responseType: 'arraybuffer'
43
+ responseType: 'arraybuffer',
44
+ cache: {
45
+ readHeaders: false,
46
+ exclude: {
47
+ query: false
48
+ },
49
+ maxAge: 0
50
+ }
43
51
  }
44
52
  }
45
53
 
46
54
  return merge(defaultConfig, config)
47
55
  }
48
56
 
57
+ utils.createClient = function (config) {
58
+ const client = axiosCacheAdapter.setup()
59
+ client.interceptors.request.use(
60
+ function (request) {
61
+ if (config.debug) {
62
+ console.log('Request:', JSON.stringify(request, null, 2))
63
+ }
64
+ return request
65
+ },
66
+ function (error) {
67
+ return Promise.reject(error)
68
+ }
69
+ )
70
+ client.interceptors.response.use(
71
+ function (response) {
72
+ if (config.debug) {
73
+ const data =
74
+ utils.isObject(response.data) || Array.isArray(response.data)
75
+ ? JSON.stringify(response.data)
76
+ : response.data.toString()
77
+ console.log(
78
+ 'Response:',
79
+ JSON.stringify(
80
+ {
81
+ headers: response.headers,
82
+ data,
83
+ fromCache: response.request.fromCache === true
84
+ },
85
+ null,
86
+ 2
87
+ )
88
+ )
89
+ }
90
+
91
+ clearTimeout(timeout)
92
+ return response
93
+ },
94
+ function (error) {
95
+ clearTimeout(timeout)
96
+ return Promise.reject(error)
97
+ }
98
+ )
99
+
100
+ return client
101
+ }
102
+
49
103
  utils.parseChannels = function (xml) {
50
104
  const result = convert.xml2js(xml)
51
105
  const siteTag = result.elements.find(el => el.name === 'site') || {}
@@ -205,10 +259,6 @@ utils.buildRequest = async function (item, config) {
205
259
  request.data = await utils.getRequestData(item, config)
206
260
  request.cancelToken = source.token
207
261
 
208
- if (config.debug) {
209
- console.log('Request:', JSON.stringify(request, null, 2))
210
- }
211
-
212
262
  if (config.curl) {
213
263
  const curl = CurlGenerator({
214
264
  url: request.url,
@@ -222,19 +272,8 @@ utils.buildRequest = async function (item, config) {
222
272
  return request
223
273
  }
224
274
 
225
- utils.fetchData = function (request) {
226
- axios.interceptors.response.use(
227
- function (response) {
228
- clearTimeout(timeout)
229
- return response
230
- },
231
- function (error) {
232
- clearTimeout(timeout)
233
- return Promise.reject(error)
234
- }
235
- )
236
-
237
- return axios(request)
275
+ utils.fetchData = function (client, request) {
276
+ return client(request)
238
277
  }
239
278
 
240
279
  utils.getRequestHeaders = async function (item, config) {
@@ -277,24 +316,20 @@ utils.getUTCDate = function (d = null) {
277
316
  }
278
317
 
279
318
  utils.parseResponse = async (item, response, config) => {
280
- if (config.debug) {
281
- console.log(
282
- 'Response:',
283
- JSON.stringify(
284
- {
285
- headers: response.headers,
286
- data: response.data.toString()
287
- },
288
- null,
289
- 2
290
- )
291
- )
319
+ let buffer
320
+ let content
321
+ if (utils.isObject(response.data) || Array.isArray(response.data)) {
322
+ content = JSON.stringify(response.data)
323
+ buffer = Buffer.from(content, 'utf8')
324
+ } else {
325
+ content = response.data.toString()
326
+ buffer = response.data
292
327
  }
293
-
294
328
  const data = merge(item, config, {
295
- content: response.data.toString(),
296
- buffer: response.data,
297
- headers: response.headers
329
+ content,
330
+ buffer,
331
+ headers: response.headers,
332
+ request: response.request
298
333
  })
299
334
 
300
335
  if (!item.channel.logo && config.logo) {
@@ -346,4 +381,8 @@ utils.isPromise = function (promise) {
346
381
  return !!promise && typeof promise.then === 'function'
347
382
  }
348
383
 
384
+ utils.isObject = function (a) {
385
+ return !!a && a.constructor === Object
386
+ }
387
+
349
388
  module.exports = utils
@@ -2,7 +2,7 @@
2
2
  * @jest-environment node
3
3
  */
4
4
 
5
- import grabber from '../src/index'
5
+ import EPGGrabber from '../src/index'
6
6
  import axios from 'axios'
7
7
 
8
8
  jest.mock('axios')
@@ -27,7 +27,8 @@ 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, '2022-01-01', config, (data, err) => {
30
+ const grabber = new EPGGrabber(config)
31
+ grabber.grab(channel, '2022-01-01', (data, err) => {
31
32
  expect(err.message).toBe('Connection timeout')
32
33
  done()
33
34
  })
@@ -53,8 +54,9 @@ it('can grab single channel programs', done => {
53
54
  lang: 'fr',
54
55
  name: '1TV'
55
56
  }
57
+ const grabber = new EPGGrabber(config)
56
58
  grabber
57
- .grab(channel, '2022-01-01', config, (data, err) => {
59
+ .grab(channel, '2022-01-01', (data, err) => {
58
60
  if (err) {
59
61
  console.log(` Error: ${err.message}`)
60
62
  done()
@@ -1,5 +1,6 @@
1
1
  import mockAxios from 'jest-mock-axios'
2
2
  import utils from '../src/utils'
3
+ import axios from 'axios'
3
4
  import path from 'path'
4
5
  import fs from 'fs'
5
6
 
@@ -148,7 +149,7 @@ it('can fetch data', () => {
148
149
  url: 'http://example.com/20210319/1tv.json',
149
150
  withCredentials: true
150
151
  }
151
- utils.fetchData(request).then(jest.fn).catch(jest.fn)
152
+ utils.fetchData(axios, request).then(jest.fn).catch(jest.fn)
152
153
  expect(mockAxios).toHaveBeenCalledWith(
153
154
  expect.objectContaining({
154
155
  data: { accountID: '123' },