Initial Commit

This commit is contained in:
2023-09-10 21:48:48 +02:00
commit 227cca7d31
791 changed files with 165200 additions and 0 deletions

32
scripts/core/api.js Normal file
View File

@@ -0,0 +1,32 @@
const _ = require('lodash')
const file = require('./file')
const DATA_DIR = process.env.DATA_DIR || './scripts/data'
class API {
constructor(filepath) {
this.filepath = file.resolve(filepath)
}
async load() {
const data = await file.read(this.filepath)
this.collection = JSON.parse(data)
}
find(query) {
return _.find(this.collection, query)
}
all() {
return this.collection
}
}
const api = {}
api.channels = new API(`${DATA_DIR}/channels.json`)
api.regions = new API(`${DATA_DIR}/regions.json`)
api.countries = new API(`${DATA_DIR}/countries.json`)
api.subdivisions = new API(`${DATA_DIR}/subdivisions.json`)
module.exports = api

13
scripts/core/date.js Normal file
View File

@@ -0,0 +1,13 @@
const dayjs = require('dayjs')
const utc = require('dayjs/plugin/utc')
dayjs.extend(utc)
const date = {}
date.getUTC = function (d = null) {
if (typeof d === 'string') return dayjs.utc(d).startOf('d')
return dayjs.utc().startOf('d')
}
module.exports = date

76
scripts/core/db.js Normal file
View File

@@ -0,0 +1,76 @@
const nedb = require('nedb-promises')
const file = require('./file')
const DB_DIR = process.env.DB_DIR || './scripts/database'
class Database {
constructor(filepath) {
this.filepath = filepath
}
load() {
this.db = nedb.create({
filename: file.resolve(this.filepath),
autoload: true,
onload: err => {
if (err) console.error(err)
},
compareStrings: (a, b) => {
a = a.replace(/\s/g, '_')
b = b.replace(/\s/g, '_')
return a.localeCompare(b, undefined, {
sensitivity: 'accent',
numeric: true
})
}
})
}
removeIndex(field) {
return this.db.removeIndex(field)
}
addIndex(options) {
return this.db.ensureIndex(options)
}
compact() {
return this.db.persistence.compactDatafile()
}
stopAutocompact() {
return this.db.persistence.stopAutocompaction()
}
reset() {
return file.clear(this.filepath)
}
count(query) {
return this.db.count(query)
}
insert(doc) {
return this.db.insert(doc)
}
update(query, update) {
return this.db.update(query, update)
}
find(query) {
return this.db.find(query)
}
remove(query, options) {
return this.db.remove(query, options)
}
}
const db = {}
db.queue = new Database(`${DB_DIR}/queue.db`)
db.programs = new Database(`${DB_DIR}/programs.db`)
module.exports = db

72
scripts/core/file.js Normal file
View File

@@ -0,0 +1,72 @@
const path = require('path')
const glob = require('glob')
const fs = require('fs-extra')
const file = {}
file.list = function (pattern) {
return new Promise(resolve => {
glob(pattern, function (err, files) {
resolve(files)
})
})
}
file.getFilename = function (filepath) {
return path.parse(filepath).name
}
file.createDir = async function (dir) {
if (await file.exists(dir)) return
return fs.mkdir(dir, { recursive: true }).catch(console.error)
}
file.exists = function (filepath) {
return fs.exists(path.resolve(filepath))
}
file.read = function (filepath) {
return fs.readFile(path.resolve(filepath), { encoding: 'utf8' }).catch(console.error)
}
file.append = function (filepath, data) {
return fs.appendFile(path.resolve(filepath), data).catch(console.error)
}
file.create = function (filepath, data = '') {
filepath = path.resolve(filepath)
const dir = path.dirname(filepath)
return file
.createDir(dir)
.then(() => file.write(filepath, data))
.catch(console.error)
}
file.write = function (filepath, data = '') {
return fs.writeFile(path.resolve(filepath), data, { encoding: 'utf8' }).catch(console.error)
}
file.writeSync = function (filepath, data = '') {
return fs.writeFileSync(path.resolve(filepath), data, { encoding: 'utf8' })
}
file.clear = async function (filepath) {
if (await file.exists(filepath)) return file.write(filepath, '')
return true
}
file.resolve = function (filepath) {
return path.resolve(filepath)
}
file.dirname = function (filepath) {
return path.dirname(filepath)
}
file.basename = function (filepath) {
return path.basename(filepath)
}
module.exports = file

11
scripts/core/index.js Normal file
View File

@@ -0,0 +1,11 @@
exports.db = require('./db')
exports.logger = require('./logger')
exports.file = require('./file')
exports.parser = require('./parser')
exports.timer = require('./timer')
exports.markdown = require('./markdown')
exports.api = require('./api')
exports.date = require('./date')
exports.table = require('./table')
exports.xml = require('./xml')
exports.zip = require('./zip')

19
scripts/core/logger.js Normal file
View File

@@ -0,0 +1,19 @@
const { Signale } = require('signale')
const options = {}
const logger = new Signale(options)
logger.config({
displayLabel: false,
displayScope: false,
displayBadge: false
})
logger.memoryUsage = function () {
const used = process.memoryUsage().heapUsed / 1024 / 1024
logger.info(`memory: ${Math.round(used * 100) / 100} MB`)
}
module.exports = logger

10
scripts/core/markdown.js Normal file
View File

@@ -0,0 +1,10 @@
const markdownInclude = require('markdown-include')
const file = require('./file')
const markdown = {}
markdown.compile = function (filepath) {
markdownInclude.compileFiles(file.resolve(filepath))
}
module.exports = markdown

29
scripts/core/parser.js Normal file
View File

@@ -0,0 +1,29 @@
const file = require('./file')
const grabber = require('epg-grabber')
const parser = {}
parser.parseChannels = async function (filepath) {
const content = await file.read(filepath)
return grabber.parseChannels(content)
}
parser.parseLogs = async function (filepath) {
const content = await file.read(filepath)
if (!content) return []
const lines = content.split('\n')
return lines.map(line => (line ? JSON.parse(line) : null)).filter(l => l)
}
parser.parseNumber = function (string) {
const parsed = parseInt(string)
if (isNaN(parsed)) {
throw new Error('scripts/core/parser.js:parseNumber() Input value is not a number')
}
return parsed
}
module.exports = parser

47
scripts/core/table.js Normal file
View File

@@ -0,0 +1,47 @@
const table = {}
table.create = function (data, cols) {
let output = '<table>\r\n'
output += ' <thead>\r\n <tr>'
for (let column of cols) {
output += `<th align="left">${column}</th>`
}
output += '</tr>\r\n </thead>\r\n'
output += ' <tbody>\r\n'
output += getHTMLRows(data)
output += ' </tbody>\r\n'
output += '</table>'
return output
}
function getHTMLRows(data) {
let output = ''
for (let group of data) {
let rowspan = group.length
for (let [j, row] of group.entries()) {
output += ' <tr>'
for (let [i, value] of row.entries()) {
if (i === 0 && j === 0) {
output += `<td valign="top" rowspan="${rowspan}">${value}</td>`
} else if (i > 0) {
if (typeof value === 'number') {
output += `<td align="right" nowrap>${value}</td>`
} else {
output += `<td nowrap>${value}</td>`
}
}
}
output += '</tr>\r\n'
}
}
return output
}
function getSpan() {}
module.exports = table

29
scripts/core/timer.js Normal file
View File

@@ -0,0 +1,29 @@
const { performance } = require('perf_hooks')
const dayjs = require('dayjs')
const duration = require('dayjs/plugin/duration')
const relativeTime = require('dayjs/plugin/relativeTime')
dayjs.extend(relativeTime)
dayjs.extend(duration)
const timer = {}
let t0 = 0
timer.start = function () {
t0 = performance.now()
}
timer.format = function (f) {
let t1 = performance.now()
return dayjs.duration(t1 - t0).format(f)
}
timer.humanize = function (suffix = true) {
let t1 = performance.now()
return dayjs.duration(t1 - t0).humanize(suffix)
}
module.exports = timer

49
scripts/core/xml.js Normal file
View File

@@ -0,0 +1,49 @@
const xml = {}
xml.create = function (items, site) {
let output = `<?xml version="1.0" encoding="UTF-8"?>\r\n<site site="${site}">\r\n <channels>\r\n`
items.forEach(channel => {
const logo = channel.logo ? ` logo="${channel.logo}"` : ''
const xmltv_id = channel.xmltv_id || ''
const lang = channel.lang || ''
const site_id = channel.site_id || ''
output += ` <channel lang="${lang}" xmltv_id="${escapeString(
xmltv_id
)}" site_id="${site_id}"${logo}>${escapeString(channel.name)}</channel>\r\n`
})
output += ` </channels>\r\n</site>\r\n`
return output
}
function escapeString(string, defaultValue = '') {
if (!string) return defaultValue
const regex = new RegExp(
'((?:[\0-\x08\x0B\f\x0E-\x1F\uFFFD\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]))|([\\x7F-\\x84]|[\\x86-\\x9F]|[\\uFDD0-\\uFDEF]|(?:\\uD83F[\\uDFFE\\uDFFF])|(?:\\uD87F[\\uDF' +
'FE\\uDFFF])|(?:\\uD8BF[\\uDFFE\\uDFFF])|(?:\\uD8FF[\\uDFFE\\uDFFF])|(?:\\uD93F[\\uDFFE\\uD' +
'FFF])|(?:\\uD97F[\\uDFFE\\uDFFF])|(?:\\uD9BF[\\uDFFE\\uDFFF])|(?:\\uD9FF[\\uDFFE\\uDFFF])' +
'|(?:\\uDA3F[\\uDFFE\\uDFFF])|(?:\\uDA7F[\\uDFFE\\uDFFF])|(?:\\uDABF[\\uDFFE\\uDFFF])|(?:\\' +
'uDAFF[\\uDFFE\\uDFFF])|(?:\\uDB3F[\\uDFFE\\uDFFF])|(?:\\uDB7F[\\uDFFE\\uDFFF])|(?:\\uDBBF' +
'[\\uDFFE\\uDFFF])|(?:\\uDBFF[\\uDFFE\\uDFFF])(?:[\\0-\\t\\x0B\\f\\x0E-\\u2027\\u202A-\\uD7FF\\' +
'uE000-\\uFFFF]|[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])|' +
'(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]))',
'g'
)
string = String(string || '').replace(regex, '')
return string
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;')
.replace(/\n|\r/g, ' ')
.replace(/ +/g, ' ')
.trim()
}
module.exports = xml

13
scripts/core/zip.js Normal file
View File

@@ -0,0 +1,13 @@
const { gzip, ungzip } = require('node-gzip')
const zip = {}
zip.compress = async function (string) {
return gzip(string)
}
zip.decompress = async function (string) {
return ungzip(string)
}
module.exports = zip