epg-grabber 0.30.2 → 0.31.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 CHANGED
@@ -80,6 +80,7 @@ Arguments:
80
80
  - `--days`: number of days for which to grab the program (default: `1`)
81
81
  - `--delay`: delay between requests in milliseconds (default: `3000`)
82
82
  - `--timeout`: set a timeout for each request in milliseconds (default: `5000`)
83
+ - `--max-connections`: set a limit on the number of concurrent requests per site (default: `1`)
83
84
  - `--cache-ttl`: maximum time for storing each request in milliseconds (default: `0`)
84
85
  - `--gzip`: compress the output (default: `false`)
85
86
  - `--debug`: enable debug mode (default: `false`)
@@ -97,6 +98,7 @@ module.exports = {
97
98
  lang: 'fr', // default language for all programs (default: 'en')
98
99
  days: 3, // number of days for which to grab the program (default: 1)
99
100
  delay: 5000, // delay between requests (default: 3000)
101
+ maxConnections: 200, // limit on the number of concurrent requests (default: 1)
100
102
 
101
103
  request: { // request options (details: https://github.com/axios/axios#request-config)
102
104
 
@@ -12,6 +12,7 @@ const { name, version, description } = require('../package.json')
12
12
  const _ = require('lodash')
13
13
  const dayjs = require('dayjs')
14
14
  const utc = require('dayjs/plugin/utc')
15
+ const { TaskQueue } = require('cwait')
15
16
 
16
17
  dayjs.extend(utc)
17
18
 
@@ -26,6 +27,11 @@ program
26
27
  .option('--days <days>', 'Number of days for which to grab the program', parseNumber)
27
28
  .option('--delay <delay>', 'Delay between requests (in milliseconds)', parseNumber)
28
29
  .option('--timeout <timeout>', 'Set a timeout for each request (in milliseconds)', parseNumber)
30
+ .option(
31
+ '--max-connections <maxConnections>',
32
+ 'Set a limit on the number of concurrent requests per site',
33
+ parseNumber
34
+ )
29
35
  .option(
30
36
  '--cache-ttl <cacheTtl>',
31
37
  'Maximum time for storing each request (in milliseconds)',
@@ -53,6 +59,7 @@ async function main() {
53
59
  curl: options.curl,
54
60
  lang: options.lang,
55
61
  delay: options.delay,
62
+ maxConnections: options.maxConnections,
56
63
  request: {}
57
64
  })
58
65
 
@@ -89,33 +96,45 @@ async function main() {
89
96
  let programs = []
90
97
  let i = 1
91
98
  let days = config.days || 1
99
+ const maxConnections = config.maxConnections || 1
92
100
  const total = channels.length * days
93
101
  const utcDate = getUTCDate()
94
102
  const dates = Array.from({ length: days }, (_, i) => utcDate.add(i, 'd'))
103
+ const taskQueue = new TaskQueue(Promise, maxConnections)
104
+
105
+ let queue = []
95
106
  for (let channel of channels) {
96
107
  if (!channel.logo && config.logo) {
97
108
  channel.logo = await grabber.loadLogo(channel)
98
109
  }
99
110
 
100
111
  for (let date of dates) {
101
- await grabber
102
- .grab(channel, date, (data, err) => {
103
- logger.info(
104
- `[${i}/${total}] ${config.site} - ${data.channel.xmltv_id} - ${dayjs
105
- .utc(data.date)
106
- .format('MMM D, YYYY')} (${data.programs.length} programs)`
107
- )
108
-
109
- if (err) logger.error(err.message)
110
-
111
- if (i < total) i++
112
- })
113
- .then(results => {
114
- programs = programs.concat(results)
115
- })
112
+ queue.push({ channel, date })
116
113
  }
117
114
  }
118
115
 
116
+ await Promise.all(
117
+ queue.map(
118
+ taskQueue.wrap(async ({ channel, date }) => {
119
+ await grabber
120
+ .grab(channel, date, (data, err) => {
121
+ logger.info(
122
+ `[${i}/${total}] ${config.site} - ${data.channel.xmltv_id} - ${dayjs
123
+ .utc(data.date)
124
+ .format('MMM D, YYYY')} (${data.programs.length} programs)`
125
+ )
126
+
127
+ if (err) logger.error(err.message)
128
+
129
+ if (i < total) i++
130
+ })
131
+ .then(results => {
132
+ programs = programs.concat(results)
133
+ })
134
+ })
135
+ )
136
+ )
137
+
119
138
  programs = _.uniqBy(programs, p => p.start + p.channel)
120
139
 
121
140
  const xml = generateXMLTV({ channels, programs })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "epg-grabber",
3
- "version": "0.30.2",
3
+ "version": "0.31.0",
4
4
  "description": "Node.js CLI tool for grabbing EPG from different sites",
5
5
  "main": "src/index.js",
6
6
  "preferGlobal": true,
@@ -34,6 +34,7 @@
34
34
  "axios-mock-adapter": "^1.20.0",
35
35
  "commander": "^7.1.0",
36
36
  "curl-generator": "^0.2.0",
37
+ "cwait": "^1.1.2",
37
38
  "dayjs": "^1.10.4",
38
39
  "epg-parser": "^0.1.6",
39
40
  "fs-extra": "^11.1.1",
package/src/client.js CHANGED
@@ -13,125 +13,125 @@ module.exports.parseResponse = parseResponse
13
13
  let timeout
14
14
 
15
15
  function create(config) {
16
- const client = setupCache(
17
- axios.create({
18
- headers: {
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
- )
24
-
25
- client.interceptors.request.use(
26
- function (request) {
27
- if (config.debug) {
28
- console.log('Request:', JSON.stringify(request, null, 2))
29
- }
30
- return request
31
- },
32
- function (error) {
33
- return Promise.reject(error)
34
- }
35
- )
36
-
37
- client.interceptors.response.use(
38
- function (response) {
39
- if (config.debug) {
40
- const data =
41
- isObject(response.data) || Array.isArray(response.data)
42
- ? JSON.stringify(response.data)
43
- : response.data.toString()
44
- console.log(
45
- 'Response:',
46
- JSON.stringify(
47
- {
48
- headers: response.headers,
49
- data,
50
- cached: response.cached
51
- },
52
- null,
53
- 2
54
- )
55
- )
56
- }
57
-
58
- clearTimeout(timeout)
59
- return response
60
- },
61
- function (error) {
62
- clearTimeout(timeout)
63
- return Promise.reject(error)
64
- }
65
- )
66
-
67
- return client
16
+ const client = setupCache(
17
+ axios.create({
18
+ headers: {
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
+ )
24
+
25
+ client.interceptors.request.use(
26
+ function (request) {
27
+ if (config.debug) {
28
+ console.log('Request:', JSON.stringify(request, null, 2))
29
+ }
30
+ return request
31
+ },
32
+ function (error) {
33
+ return Promise.reject(error)
34
+ }
35
+ )
36
+
37
+ client.interceptors.response.use(
38
+ function (response) {
39
+ if (config.debug) {
40
+ const data =
41
+ isObject(response.data) || Array.isArray(response.data)
42
+ ? JSON.stringify(response.data)
43
+ : response.data.toString()
44
+ console.log(
45
+ 'Response:',
46
+ JSON.stringify(
47
+ {
48
+ headers: response.headers,
49
+ data,
50
+ cached: response.cached
51
+ },
52
+ null,
53
+ 2
54
+ )
55
+ )
56
+ }
57
+
58
+ clearTimeout(timeout)
59
+ return response
60
+ },
61
+ function (error) {
62
+ clearTimeout(timeout)
63
+ return Promise.reject(error)
64
+ }
65
+ )
66
+
67
+ return client
68
68
  }
69
69
 
70
70
  async function buildRequest({ channel, date, config }) {
71
- const CancelToken = axios.CancelToken
72
- const source = CancelToken.source()
73
- const request = { ...config.request }
74
- timeout = setTimeout(() => {
75
- source.cancel('Connection timeout')
76
- }, request.timeout)
77
- request.headers = await getRequestHeaders({ channel, date, config })
78
- request.url = await getRequestUrl({ channel, date, config })
79
- request.data = await getRequestData({ channel, date, config })
80
- request.cancelToken = source.token
81
-
82
- if (config.curl) {
83
- const curl = CurlGenerator({
84
- url: request.url,
85
- method: request.method,
86
- headers: request.headers,
87
- body: request.data
88
- })
89
- console.log(curl)
90
- }
91
-
92
- return request
71
+ const CancelToken = axios.CancelToken
72
+ const source = CancelToken.source()
73
+ const request = { ...config.request }
74
+ timeout = setTimeout(() => {
75
+ source.cancel('Connection timeout')
76
+ }, request.timeout)
77
+ request.headers = await getRequestHeaders({ channel, date, config })
78
+ request.url = await getRequestUrl({ channel, date, config })
79
+ request.data = await getRequestData({ channel, date, config })
80
+ request.cancelToken = source.token
81
+
82
+ if (config.curl) {
83
+ const curl = CurlGenerator({
84
+ url: request.url,
85
+ method: request.method,
86
+ headers: request.headers,
87
+ body: request.data
88
+ })
89
+ console.log(curl)
90
+ }
91
+
92
+ return request
93
93
  }
94
94
 
95
95
  function parseResponse(response) {
96
- return {
97
- content: response.data.toString(),
98
- buffer: response.data,
99
- headers: response.headers,
100
- request: response.request,
101
- cached: response.cached
102
- }
96
+ return {
97
+ content: response.data.toString(),
98
+ buffer: response.data,
99
+ headers: response.headers,
100
+ request: response.request,
101
+ cached: response.cached
102
+ }
103
103
  }
104
104
 
105
105
  async function getRequestHeaders({ channel, date, config }) {
106
- if (typeof config.request.headers === 'function') {
107
- const headers = config.request.headers({ channel, date })
108
- if (isPromise(headers)) {
109
- return await headers
110
- }
111
- return headers
112
- }
113
-
114
- return config.request.headers || null
106
+ if (typeof config.request.headers === 'function') {
107
+ const headers = config.request.headers({ channel, date })
108
+ if (isPromise(headers)) {
109
+ return await headers
110
+ }
111
+ return headers
112
+ }
113
+
114
+ return config.request.headers || null
115
115
  }
116
116
 
117
117
  async function getRequestData({ channel, date, config }) {
118
- if (typeof config.request.data === 'function') {
119
- const data = config.request.data({ channel, date })
120
- if (isPromise(data)) {
121
- return await data
122
- }
123
- return data
124
- }
125
- return config.request.data || null
118
+ if (typeof config.request.data === 'function') {
119
+ const data = config.request.data({ channel, date })
120
+ if (isPromise(data)) {
121
+ return await data
122
+ }
123
+ return data
124
+ }
125
+ return config.request.data || null
126
126
  }
127
127
 
128
128
  async function getRequestUrl({ channel, date, config }) {
129
- if (typeof config.url === 'function') {
130
- const url = config.url({ channel, date })
131
- if (isPromise(url)) {
132
- return await url
133
- }
134
- return url
135
- }
136
- return config.url
129
+ if (typeof config.url === 'function') {
130
+ const url = config.url({ channel, date })
131
+ if (isPromise(url)) {
132
+ return await url
133
+ }
134
+ return url
135
+ }
136
+ return config.url
137
137
  }
@@ -1,4 +1,4 @@
1
- <?xml version="1.0" encoding="UTF-8" ?><tv date="20230511">
1
+ <?xml version="1.0" encoding="UTF-8" ?><tv date="20230521">
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><url>https://example.com</url></channel>
4
4
  <programme start="20220101000000 +0000" stop="20220101010000 +0000" channel="1TV.com"><title lang="fr">Program1</title></programme>