Merge pull request #3 from freearhey/v0.8.0

v0.8.0
This commit is contained in:
Aleksandr Statciuk 2021-09-16 00:40:04 +03:00 committed by GitHub
commit c58852ef33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 91 additions and 31 deletions

View File

@ -17,17 +17,23 @@ epg-grabber --config=example.com.config.js
Arguments:
- `-c, --config`: path to config file
- `-d, --debug`: enable debug mode
- `-o, --output`: path to output file (default: 'guide.xml')
- `--channels`: path to list of channels (can be specified via config file)
- `--lang`: set default language for all programs (default: 'en')
- `--days`: number of days for which to grab the program (default: 1)
- `--delay`: delay between requests (default: 3000)
- `--debug`: enable debug mode (default: false)
#### example.com.config.js
```js
module.exports = {
lang: 'fr', // default language for all programs (default: 'en')
site: 'example.com', // site domain name (required)
output: 'example.com.guide.xml', // path to output file (default: 'guide.xml')
channels: 'example.com.channels.xml', // path to channels.xml file (required)
lang: 'fr', // default language for all programs (default: 'en')
days: 3, // number of days for which to grab the program (default: 1)
delay: 5000, // delay between requests (default: 3000)
request: { // request options (details: https://github.com/axios/axios#request-config)

28
package-lock.json generated
View File

@ -1,11 +1,12 @@
{
"name": "epg-grabber",
"version": "0.4.1",
"version": "0.7.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"version": "0.4.1",
"name": "epg-grabber",
"version": "0.7.0",
"license": "MIT",
"dependencies": {
"axios": "^0.21.1",
@ -1652,7 +1653,6 @@
"jest-resolve": "^26.6.2",
"jest-util": "^26.6.2",
"jest-worker": "^26.6.2",
"node-notifier": "^8.0.0",
"slash": "^3.0.0",
"source-map": "^0.6.0",
"string-length": "^4.0.1",
@ -2742,10 +2742,14 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001205",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001205.tgz",
"integrity": "sha512-TL1GrS5V6LElbitPazidkBMD9sa448bQDDLrumDqaggmKFcuU2JW1wTOHJPukAcOMtEmLcmDJEzfRrf+GjM0Og==",
"dev": true
"version": "1.0.30001257",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
"dev": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
}
},
"node_modules/capture-exit": {
"version": "2.0.0",
@ -3338,8 +3342,7 @@
"esprima": "^4.0.1",
"estraverse": "^5.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
"optionator": "^0.8.1"
},
"bin": {
"escodegen": "bin/escodegen.js",
@ -5371,7 +5374,6 @@
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"fsevents": "^2.1.2",
"graceful-fs": "^4.2.4",
"jest-regex-util": "^26.0.0",
"jest-serializer": "^26.6.2",
@ -11788,9 +11790,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001205",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001205.tgz",
"integrity": "sha512-TL1GrS5V6LElbitPazidkBMD9sa448bQDDLrumDqaggmKFcuU2JW1wTOHJPukAcOMtEmLcmDJEzfRrf+GjM0Og==",
"version": "1.0.30001257",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz",
"integrity": "sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA==",
"dev": true
},
"capture-exit": {

View File

@ -1,6 +1,6 @@
{
"name": "epg-grabber",
"version": "0.7.0",
"version": "0.8.0",
"description": "Node.js CLI tool for grabbing EPG from different sites",
"main": "src/index.js",
"preferGlobal": true,
@ -20,6 +20,10 @@
],
"author": "Arhey",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/freearhey/epg-grabber.git"
},
"engines": {
"node": ">=10.0.0"
},

View File

@ -10,11 +10,16 @@ program
.version(version, '-v, --version')
.description(description)
.option('-c, --config <config>', 'Path to [site].config.js file')
.option('-d, --debug', 'Enable debug mode')
.option('-o, --output <output>', 'Path to output file', 'guide.xml')
.option('--channels <channels>', 'Path to channels.xml file')
.option('--lang <lang>', 'Set default language for all programs', 'en')
.option('--days <days>', 'Number of days for which to grab the program', 1)
.option('--delay <delay>', 'Delay between requests (in mileseconds)', 3000)
.option('--debug', 'Enable debug mode', false)
.parse(process.argv)
const options = program.opts()
const config = utils.loadConfig(options.config)
const config = utils.loadConfig(options)
async function main() {
console.log('\r\nStarting...')

View File

@ -14,15 +14,19 @@ const utils = {}
const defaultUserAgent =
'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'
utils.loadConfig = function (file) {
utils.loadConfig = function (options) {
const file = options.config
if (!file) throw new Error('Path to [site].config.js is missing')
console.log(`Loading '${file}'...`)
const configPath = path.resolve(file)
const config = require(configPath)
if (options.channels) config.channels = options.channels
else if (config.channels) config.channels = path.join(path.dirname(file), config.channels)
else throw new Error("The required 'channels' property is missing")
if (!config.site) throw new Error("The required 'site' property is missing")
if (!config.channels) throw new Error("The required 'channels' property is missing")
if (!config.url) throw new Error("The required 'url' property is missing")
if (typeof config.url !== 'function' && typeof config.url !== 'string')
throw new Error("The 'url' property should return the function or string")
@ -32,13 +36,11 @@ utils.loadConfig = function (file) {
if (config.logo && typeof config.logo !== 'function')
throw new Error("The 'logo' property should return the function")
config.channels = path.join(path.dirname(file), config.channels)
const defaultConfig = {
days: 1,
lang: 'en',
delay: 3000,
output: 'guide.xml',
days: options.days ? parseInt(options.days) : 1,
lang: options.lang || 'en',
delay: options.delay ? parseInt(options.delay) : 3000,
output: options.output || 'guide.xml',
request: {
method: 'GET',
maxContentLength: 5 * 1024 * 1024,

1
tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
output/

34
tests/index.test.js Normal file
View File

@ -0,0 +1,34 @@
const { execSync } = require('child_process')
const pwd = `${__dirname}/..`
function stdoutResultTester(stdout) {
return [`Finish`].every(val => {
return RegExp(val).test(stdout)
})
}
it('can load config', () => {
const result = execSync(`node ${pwd}/src/index.js --config=tests/input/example.com.config.js`, {
encoding: 'utf8'
})
expect(stdoutResultTester(result)).toBe(true)
})
it('can load mini config', () => {
const result = execSync(
`node ${pwd}/src/index.js \
--config=tests/input/mini.config.js \
--channels=tests/input/example.com.channels.xml \
--output=tests/output/mini.guide.xml \
--lang=fr \
--days=3 \
--delay=5000`,
{
encoding: 'utf8'
}
)
expect(stdoutResultTester(result)).toBe(true)
expect(result.includes("File 'tests/output/mini.guide.xml' successfully saved")).toBe(true)
})

View File

@ -1,6 +1,7 @@
module.exports = {
site: 'example.com',
channels: 'example.com.channels.xml',
output: 'tests/output/guide.xml',
url: () => 'http://example.com/20210319/1tv.json',
request: {
method: 'POST',

View File

@ -0,0 +1,5 @@
module.exports = {
site: 'example.com',
url: () => 'http://example.com/20210319/1tv.json',
parser: () => []
}

View File

@ -2,13 +2,13 @@ import mockAxios from 'jest-mock-axios'
import utils from '../src/utils'
it('can load valid config.js', () => {
const config = utils.loadConfig('./tests/input/example.com.config.js')
const config = utils.loadConfig({ config: './tests/input/example.com.config.js' })
expect(config).toMatchObject({
channels: 'tests/input/example.com.channels.xml',
days: 1,
delay: 3000,
lang: 'en',
output: 'guide.xml',
output: 'tests/output/guide.xml',
site: 'example.com'
})
expect(config.request).toMatchObject({
@ -115,7 +115,7 @@ it('can fetch data', async () => {
})
it('can build request async', async () => {
const config = utils.loadConfig('./tests/input/async.config.js')
const config = utils.loadConfig({ config: './tests/input/async.config.js' })
return utils.buildRequest({}, config).then(request => {
expect(request).toMatchObject({
data: { accountID: '123' },
@ -136,14 +136,14 @@ it('can build request async', async () => {
})
it('can load logo async', async () => {
const config = utils.loadConfig('./tests/input/async.config.js')
const config = utils.loadConfig({ config: './tests/input/async.config.js' })
return utils.loadLogo({}, config).then(logo => {
expect(logo).toBe('http://example.com/logos/1TV.png?x=шеллы&sid=777')
})
})
it('can parse programs async', async () => {
const config = utils.loadConfig('./tests/input/async.config.js')
const config = utils.loadConfig({ config: './tests/input/async.config.js' })
return utils
.parsePrograms({ channel: { xmltv_id: '1tv', lang: 'en' } }, config)
.then(programs => {