李勇

提交线上服务使用的版本

ALIBABA_CLOUD_ACCESS_KEY_ID='LTAI4G7fEeS2Mg9LuChgHpzg'
ALIBABA_CLOUD_ACCESS_KEY_SECRET='azh5WqDfS1wQo0TZgtJ0yr0vk827PW'
... ...
... ... @@ -5,6 +5,7 @@ var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var bbgRecordingRouter = require('./routes/bbgRecording');
var app = express();
... ... @@ -18,7 +19,18 @@ app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.all("*",function(req,res,next){
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin","*");
//允许的header类型
res.header("Access-Control-Allow-Headers","content-type");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods","POST,OPTIONS");
next();
});
app.use('/', indexRouter);
app.use('/mp4record',bbgRecordingRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
... ... @@ -28,12 +40,13 @@ app.use(function(req, res, next) {
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
//res.locals.message = err.message;
//res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
// res.status(err.status || 500);
//res.render('error');
res.send({ code: err.status || 500 });
});
module.exports = app;
... ...
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
... ...
... ... @@ -12,7 +12,8 @@ var http = require('http');
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3001');
var port = normalizePort( '3001');
console.log("port",port)
app.set('port', port);
/**
... ...
{
"GETCLASSURL":"http://139.196.126.156:8081/getLogs/recordClassList",
"GETCLASSURL":"https://log3.xuedianyun.com/getLogs/recordClassList",
"GETCLASSURLPARAMETER":{
"siteId":["beidatest"],
"siteId":["chindle","skyy","hopefound","beidatest"],
"key":"xdymp4record20191225",
"page":1,
"maxMedia":1
"maxMedia":23
},
"PROJECTWINCATALOG":"F:/project/web_capture_release/win-x64",
"PROJECTCATALOG":"F:/project/web_capture_release",
"PROJECTWINCATALOG":"/root/web_capture_release/linux-x64",
"PROJECTCATALOG":"/root/web_capture_release",
"BACKMEDIACONFIG":{
"url" : "https://pclive.xuedianyun.com/pcBase/pclive2/dev/index.html",
"recordMp4":true,
... ... @@ -25,5 +25,6 @@
"k":0,
"w":1280,
"h":720
}
}
\ No newline at end of file
},
"classLastNumber":["0","1","2","3","4","5","6","7","8","9"]
}
... ...
... ... @@ -5,38 +5,49 @@ const methods = {
let YesterdayTime = (new Date).getTime() - 24 * 60 * 60 * 1000
let YesterdayTimeDate = new Date(YesterdayTime)
let year = YesterdayTimeDate.getFullYear()
year = year.toString()
let month = YesterdayTimeDate.getMonth() + 1
let date = YesterdayTimeDate.getDate()
let startTime = new Date(year + "-" + month + "-" + date + " 5:30:00").getTime()
let endTime = new Date(year + "-" + month + "-" + date + " 23:59:00").getTime()
if(month < 10){
if (month < 10) {
month = '0' + month
}else{
month = month.toString()
}
if(date < 10){
if (date < 10) {
date = '0' + date
}else{
date = date.toString()
}
return {
startTime,
endTime,
ymd:year+month+date
ymd: year + month + date
}
},
dayTimeYMD() {
let dayTimeDate = new Date()
let year = dayTimeDate.getFullYear()
year = year.toString()
let month = dayTimeDate.getMonth() + 1
let date = dayTimeDate.getDate()
if(month < 10){
if (month < 10) {
month = '0' + month
}else{
month = month.toString()
}
if(date < 10){
if (date < 10) {
date = '0' + date
}else{
date = date.toString()
}
return {
ymd:year + "-" + month + "-" + date
ymd: year + month + date
}
},
async getRequestClassIds(url, siteId, key, startTime, endTime,page) {
async getRequestClassIds(url, siteId, key, startTime, endTime, page) {
let axiosUrl = `${url}?siteId=${siteId}&key=${key}&from=${startTime}&to=${endTime}&page=${page}`
let result = await axios.get(axiosUrl)
return result
... ...
{
"PROJECTWINCATALOG":"/root/web_capture_release/linux-x64",
"PROJECTCATALOG":"/oss/oss",
"BACKMEDIACONFIG": {
"url": "https://pclive.xuedianyun.com/pcBase/pclive2/dev/index.html",
"recordMp4": true,
"classId": "",
"userId": 0,
"userName": "",
"userRole": "invisible",
"portalIP": "saas.xuedianyun.com",
"portalPort": 80,
"channels": 0,
"playRecord": 1,
"d": 21600000,
"s": 3000,
"fa": 15,
"k": 0,
"w": 1280,
"h": 720
}
}
... ...
... ... @@ -26,6 +26,80 @@
"acorn": "^2.1.0"
}
},
"address": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/address/-/address-1.2.2.tgz",
"integrity": "sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA=="
},
"agentkeepalive": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.3.tgz",
"integrity": "sha512-yqXL+k5rr8+ZRpOAntkaaRgWgE5o8ESAj5DyRmVTCSoZxXmqemb9Dd7T4i5UzwuERdLAJUy6XzR9zFVuf0kzkw==",
"requires": {
"humanize-ms": "^1.2.1"
}
},
"ali-oss": {
"version": "6.22.0",
"resolved": "https://registry.npmjs.org/ali-oss/-/ali-oss-6.22.0.tgz",
"integrity": "sha512-X8CHo+wsjCBvDaEvuibFOi3SZxiCBZSRUURrXH0upoVwu3SuW3e+PTVK7xw+uN6EyTcAESqrngrQimhp8iBzsQ==",
"requires": {
"address": "^1.2.2",
"agentkeepalive": "^3.4.1",
"bowser": "^1.6.0",
"copy-to": "^2.0.1",
"dateformat": "^2.0.0",
"debug": "^4.3.4",
"destroy": "^1.0.4",
"end-or-error": "^1.0.1",
"get-ready": "^1.0.0",
"humanize-ms": "^1.2.0",
"is-type-of": "^1.4.0",
"js-base64": "^2.5.2",
"jstoxml": "^2.0.0",
"lodash": "^4.17.21",
"merge-descriptors": "^1.0.1",
"mime": "^2.4.5",
"platform": "^1.3.1",
"pump": "^3.0.0",
"qs": "^6.4.0",
"sdk-base": "^2.0.1",
"stream-http": "2.8.2",
"stream-wormhole": "^1.0.4",
"urllib": "^2.44.0",
"utility": "^1.18.0",
"xml2js": "^0.6.2"
},
"dependencies": {
"debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
"integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
"requires": {
"ms": "^2.1.3"
}
},
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
},
"ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
}
}
},
"align-text": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
... ... @@ -41,6 +115,11 @@
"resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
},
"any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
},
"array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
... ... @@ -97,6 +176,11 @@
"type-is": "~1.6.16"
}
},
"bowser": {
"version": "1.9.4",
"resolved": "https://registry.npmjs.org/bowser/-/bowser-1.9.4.tgz",
"integrity": "sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
... ... @@ -106,6 +190,11 @@
"concat-map": "0.0.1"
}
},
"builtin-status-codes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
"integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ=="
},
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
... ... @@ -218,6 +307,16 @@
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
"integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
},
"copy-to": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz",
"integrity": "sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w=="
},
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
"css": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/css/-/css-1.0.8.tgz",
... ... @@ -237,6 +336,16 @@
"resolved": "https://registry.npmjs.org/css-stringify/-/css-stringify-1.0.5.tgz",
"integrity": "sha1-sNBClG2ylTu50pKQCmy19tASIDE="
},
"date-format": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-3.0.0.tgz",
"integrity": "sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w=="
},
"dateformat": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
"integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
... ... @@ -250,6 +359,14 @@
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"default-user-agent": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/default-user-agent/-/default-user-agent-1.0.0.tgz",
"integrity": "sha512-bDF7bg6OSNcSwFWPu4zYKpVkJZQYVrAANMYB8bc9Szem1D0yKdm4sa/rOCs2aC9+2GMqQ7KnwtZRvDhmLF0dXw==",
"requires": {
"os-name": "~1.0.3"
}
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
... ... @@ -268,6 +385,16 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"digest-header": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/digest-header/-/digest-header-1.1.0.tgz",
"integrity": "sha512-glXVh42vz40yZb9Cq2oMOt70FIoWiv+vxNvdKdU8CwjLad25qHM3trLxhl9bVjdr6WaslIXhWpn0NO8T/67Qjg=="
},
"dotenv": {
"version": "16.4.7",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
"integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ=="
},
"ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
... ... @@ -278,6 +405,19 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"end-of-stream": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
"requires": {
"once": "^1.4.0"
}
},
"end-or-error": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/end-or-error/-/end-or-error-1.0.1.tgz",
"integrity": "sha512-OclLMSug+k2A0JKuf494im25ANRBVW8qsjmwbgX7lQ8P82H21PQ1PWkoYwb9y5yMBS69BPlwtzdIFClo3+7kOQ=="
},
"es-abstract": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.0.tgz",
... ... @@ -311,6 +451,15 @@
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"esdk-obs-nodejs": {
"version": "3.20.11",
"resolved": "https://registry.npmjs.org/esdk-obs-nodejs/-/esdk-obs-nodejs-3.20.11.tgz",
"integrity": "sha512-pFdlFIV24yLXYwIg6UZz/xFHom5bTF+D5yyJHxngoP4o6KfxVIid3BTMPLh6MVTpSLBgiTwiGKfvvAJavH240g==",
"requires": {
"log4js": "^6.3.0",
"xml2js": "^0.4.23"
}
},
"etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
... ... @@ -353,6 +502,14 @@
"vary": "~1.1.2"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"requires": {
"is-extendable": "^0.1.0"
}
},
"finalhandler": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
... ... @@ -367,6 +524,11 @@
"unpipe": "~1.0.0"
}
},
"flatted": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz",
"integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA=="
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
... ... @@ -385,6 +547,24 @@
}
}
},
"formstream": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/formstream/-/formstream-1.5.1.tgz",
"integrity": "sha512-q7ORzFqotpwn3Y/GBK2lK7PjtZZwJHz9QE9Phv8zb5IrL9ftGLyi2zjGURON3voK8TaZ+mqJKERYN4lrHYTkUQ==",
"requires": {
"destroy": "^1.0.4",
"mime": "^2.5.2",
"node-hex": "^1.0.1",
"pause-stream": "~0.0.11"
},
"dependencies": {
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
"integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="
}
}
},
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
... ... @@ -395,6 +575,16 @@
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
},
"fs-extra": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
"integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
... ... @@ -405,6 +595,11 @@
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-ready": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/get-ready/-/get-ready-1.0.0.tgz",
"integrity": "sha512-mFXCZPJIlcYcth+N8267+mghfYN9h3EhsDa6JSnbA3Wrhh/XFpuowviFcsDeYZtKspQyWyJqfs4O6P8CHeTwzw=="
},
"glob": {
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
... ... @@ -418,6 +613,11 @@
"path-is-absolute": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
},
"graceful-readlink": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
... ... @@ -447,6 +647,14 @@
"statuses": ">= 1.4.0 < 2"
}
},
"humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"requires": {
"ms": "^2.0.0"
}
},
"iconv-lite": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
... ... @@ -494,11 +702,21 @@
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q=="
},
"is-class-hotfix": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz",
"integrity": "sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ=="
},
"is-date-object": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw=="
},
"is-generator-function": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",
... ... @@ -525,6 +743,26 @@
"has-symbols": "^1.0.1"
}
},
"is-type-of": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/is-type-of/-/is-type-of-1.4.0.tgz",
"integrity": "sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==",
"requires": {
"core-util-is": "^1.0.2",
"is-class-hotfix": "~0.0.6",
"isstream": "~0.1.2"
}
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
"jade": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/jade/-/jade-1.11.0.tgz",
... ... @@ -542,6 +780,24 @@
"with": "~4.0.0"
}
},
"js-base64": {
"version": "2.6.4",
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz",
"integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ=="
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"requires": {
"graceful-fs": "^4.1.6"
}
},
"jstoxml": {
"version": "2.2.9",
"resolved": "https://registry.npmjs.org/jstoxml/-/jstoxml-2.2.9.tgz",
"integrity": "sha512-OYWlK0j+roh+eyaMROlNbS5cd5R25Y+IUpdl7cNdB8HNrkgwQzIS7L9MegxOiWNBj9dQhA/yAxiMwCC5mwNoBw=="
},
"jstransformer": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-0.0.2.tgz",
... ... @@ -564,6 +820,38 @@
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
"integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"log4js": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/log4js/-/log4js-6.3.0.tgz",
"integrity": "sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==",
"requires": {
"date-format": "^3.0.0",
"debug": "^4.1.1",
"flatted": "^2.0.1",
"rfdc": "^1.1.4",
"streamroller": "^2.2.4"
},
"dependencies": {
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"longest": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
... ... @@ -640,11 +928,31 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"mz": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
"requires": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
"thenify-all": "^1.0.0"
}
},
"negotiator": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
},
"node-hex": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/node-hex/-/node-hex-1.0.1.tgz",
"integrity": "sha512-iwpZdvW6Umz12ICmu9IYPRxg0tOLGmU3Tq2tKetejCj3oZd7b2nUXwP3a7QA5M9glWy8wlPS1G3RwM/CdsUbdQ=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
},
"object-inspect": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
... ... @@ -706,6 +1014,30 @@
"wordwrap": "~0.0.2"
}
},
"os-name": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz",
"integrity": "sha512-f5estLO2KN8vgtTRaILIgEGBoBrMnZ3JQ7W9TMZCnOIGwHe8TRGSpcagnWDo+Dfhd/z08k9Xe75hvciJJ8Qaew==",
"requires": {
"osx-release": "^1.0.0",
"win-release": "^1.0.0"
}
},
"osx-release": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz",
"integrity": "sha512-ixCMMwnVxyHFQLQnINhmIpWqXIfS2YOXchwQrk+OFzmo6nDjQ0E4KXAyyUh0T0MZgV4bUhkRrAbVqlE4yLVq4A==",
"requires": {
"minimist": "^1.1.0"
},
"dependencies": {
"minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
}
}
},
"parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
... ... @@ -726,6 +1058,24 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pause-stream": {
"version": "0.0.11",
"resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
"integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
"requires": {
"through": "~2.3"
}
},
"platform": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
"integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg=="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"promise": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/promise/-/promise-6.1.0.tgz",
... ... @@ -743,6 +1093,15 @@
"ipaddr.js": "1.9.0"
}
},
"pump": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
"integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==",
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
... ... @@ -764,6 +1123,20 @@
"unpipe": "1.0.0"
}
},
"readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
... ... @@ -785,6 +1158,11 @@
"path-parse": "^1.0.6"
}
},
"rfdc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.2.0.tgz",
"integrity": "sha512-ijLyszTMmUrXvjSooucVQwimGUk84eRcmCuLV8Xghe3UO85mjUtRAHRyoMM6XtyqbECaXuBWx18La3523sXINA=="
},
"right-align": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
... ... @@ -803,6 +1181,24 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"sdk-base": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/sdk-base/-/sdk-base-2.0.1.tgz",
"integrity": "sha512-eeG26wRwhtwYuKGCDM3LixCaxY27Pa/5lK4rLKhQa7HBjJ3U3Y+f81MMZQRsDw/8SC2Dao/83yJTXJ8aULuN8Q==",
"requires": {
"get-ready": "~1.0.0"
}
},
"semver": {
"version": "5.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
"integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="
},
"send": {
"version": "0.16.2",
"resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
... ... @@ -862,6 +1258,53 @@
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
"integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
},
"stream-http": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz",
"integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==",
"requires": {
"builtin-status-codes": "^3.0.0",
"inherits": "^2.0.1",
"readable-stream": "^2.3.6",
"to-arraybuffer": "^1.0.0",
"xtend": "^4.0.0"
}
},
"stream-wormhole": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stream-wormhole/-/stream-wormhole-1.1.0.tgz",
"integrity": "sha512-gHFfL3px0Kctd6Po0M8TzEvt3De/xu6cnRrjlfYNhwbhLPLwigI2t1nc6jrzNuaYg5C4YF78PPFuQPzRiqn9ew=="
},
"streamroller": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/streamroller/-/streamroller-2.2.4.tgz",
"integrity": "sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==",
"requires": {
"date-format": "^2.1.0",
"debug": "^4.1.1",
"fs-extra": "^8.1.0"
},
"dependencies": {
"date-format": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
"integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA=="
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
"integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
"requires": {
"ms": "2.1.2"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
... ... @@ -880,6 +1323,40 @@
"function-bind": "^1.1.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
"requires": {
"any-promise": "^1.0.0"
}
},
"thenify-all": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
"requires": {
"thenify": ">= 3.1.0 < 4"
}
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
},
"to-arraybuffer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
"integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA=="
},
"transformers": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/transformers/-/transformers-2.1.0.tgz",
... ... @@ -954,11 +1431,53 @@
"integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
"optional": true
},
"unescape": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/unescape/-/unescape-1.0.1.tgz",
"integrity": "sha512-O0+af1Gs50lyH1nUu3ZyYS1cRh01Q/kUKatTOkSs7jukXE6/NebucDVxyiDsA9AQ4JC1V1jUH9EO8JX2nMDgGQ==",
"requires": {
"extend-shallow": "^2.0.1"
}
},
"universalify": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
"integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"urllib": {
"version": "2.44.0",
"resolved": "https://registry.npmjs.org/urllib/-/urllib-2.44.0.tgz",
"integrity": "sha512-zRCJqdfYllRDA9bXUtx+vccyRqtJPKsw85f44zH7zPD28PIvjMqIgw9VwoTLV7xTBWZsbebUFVHU5ghQcWku2A==",
"requires": {
"any-promise": "^1.3.0",
"content-type": "^1.0.2",
"default-user-agent": "^1.0.0",
"digest-header": "^1.0.0",
"ee-first": "~1.1.1",
"formstream": "^1.1.0",
"humanize-ms": "^1.2.0",
"iconv-lite": "^0.6.3",
"pump": "^3.0.0",
"qs": "^6.4.0",
"statuses": "^1.3.1",
"utility": "^1.16.1"
},
"dependencies": {
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
}
}
},
"util": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/util/-/util-0.12.1.tgz",
... ... @@ -971,6 +1490,23 @@
"safe-buffer": "^5.1.2"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"utility": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/utility/-/utility-1.18.0.tgz",
"integrity": "sha512-PYxZDA+6QtvRvm//++aGdmKG/cI07jNwbROz0Ql+VzFV1+Z0Dy55NI4zZ7RHc9KKpBePNFwoErqIuqQv/cjiTA==",
"requires": {
"copy-to": "^2.0.1",
"escape-html": "^1.0.3",
"mkdirp": "^0.5.1",
"mz": "^2.7.0",
"unescape": "^1.0.1"
}
},
"utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
... ... @@ -986,6 +1522,14 @@
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
"integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w="
},
"win-release": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz",
"integrity": "sha512-iCRnKVvGxOQdsKhcQId2PXV1vV3J/sDPXKA4Oe9+Eti2nb2ESEsYHRYls/UjoUW3bIc5ZDO8dTH50A/5iVN+bw==",
"requires": {
"semver": "^5.0.1"
}
},
"window-size": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
... ... @@ -1017,6 +1561,25 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xml2js": {
"version": "0.4.23",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
"integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
"requires": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
}
},
"xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"yargs": {
"version": "3.10.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
... ...
... ... @@ -3,14 +3,17 @@
"version": "0.0.0",
"private": true,
"scripts": {
"start": "nodemon ./bin/www",
"start": "node ./bin/www",
"pm2": "pm2 start ./bin/www --name webScreen"
},
"dependencies": {
"ali-oss": "^6.22.0",
"axios": "^0.19.0",
"child_process": "^1.0.2",
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"dotenv": "^16.4.7",
"esdk-obs-nodejs": "^3.20.11",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"jade": "~1.11.0",
... ...
var express = require('express');
var router = express.Router();
const { exec } = require('child_process');
const fs = require("fs");
const axios = require('axios');
const method = require("../config/method")
const { dayTimeYMD } = method
let classids = []
/**
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() {
}
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
recordingCreat(id,siteId,classUrl,duration,width,height,frameRate,bitrate) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
// let mediaDir = PROJECTCATALOG + "/media/"
// let classDir = PROJECTCATALOG + "/media/" + siteId
// let ymdDir = null
// let timeDir = dayTimeYMD().ymd
// ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + timeDir
let classDir = PROJECTCATALOG + "/" + siteId
let ymdDir = null
let timeDir = dayTimeYMD().ymd
ymdDir = PROJECTCATALOG + "/" + siteId + "/" + timeDir
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
// let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
// this.wrieLog("files:" + files)
// if (files.indexOf(id + ".mp4") != -1) {
// this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
// return
// }
// if(!classUrl){
// classUrl = `${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}"`
// }
// if(!duration){
// duration = BACKMEDIACONFIG.d
// }
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${classUrl}" -d=${duration} -s=${BACKMEDIACONFIG.s} -k=${BACKMEDIACONFIG.k} -w=${width} -h=${height} -fa=${frameRate} -vb=${bitrate}`
this.wrieLog("全地址"+url)
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
// 删除已存元素
classids.splice(classids.findIndex(item => item === id),1)
return
}
// let files = fs.readdirSync(ymdDir);
// if (files.indexOf(id + ".mp4") != -1) {
// 删除已存元素
classids.splice(classids.findIndex(item => item === id),1)
this.sendMediaInfo(siteId,id,timeDir)
// }
})
}
// 上报地址
async sendMediaInfo(siteId,id,timeDir){
// https://mp4record.obs.cn-north-4.myhuaweicloud.com/oss/media/eebbktest/20210326/1657547103.mp4
// let MediaUrl = `https://mp4record.obs.cn-north-4.myhuaweicloud.com/oss/media/${siteId}/${timeDir}/${id}.mp4`
let MediaUrl = `https://mp4record.obs.cn-north-4.myhuaweicloud.com/oss/${siteId}/${timeDir}/${id}.mp4`
let urlSizeId = {
"eebbktest": "gdbbkwxyace",
"gdbbk":"gdbbkwx",
"gdbbkdev":"gdbbkwxtest"
}
let requestUrl = `https://${urlSizeId[siteId]}.xuedianyun.com/bbgserver/app/course/updateRecordUrl`
let result = await axios.post(
requestUrl,
{meetingNumber:id,url:MediaUrl},
{headers: {'orgId':siteId }}
)
if(result.data){
this.wrieLog("更新视频地址结果:"+JSON.stringify(result.data))
}
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/realTimeConfig.json")
return String(buffer)
}
}
/**
* {
* "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
* }
*/
router.post('/recording/:id', function (req, res, next) {
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
/**
* classId:课堂号
* siteId:机构编码
* url:课堂地址
* duration:录制时长
* width height 录制视频宽高
* frameRate 帧率
* bitrate 码率
*/
let { classId,siteId,url:classUrl,duration,width,height,frameRate,bitrate } = req.body
if (classId && siteId && classUrl && duration && width && height && frameRate && bitrate) {
if(!Number.isInteger(classId) || !Number.isInteger(duration) || !Number.isInteger(width) || !Number.isInteger(height) || !Number.isInteger(frameRate) || !Number.isInteger(bitrate)){
res.send({ code: "3", message: "参数类型错误" });
return
}
let maxTime = 10*60*60*1000
if(duration < 0 || duration > maxTime){
res.send({ code: "4", message: "参数范围错误" });
return
}
// 避免多次重复课堂号请求
if(!classids.includes(classId)){
// 没有正在录制的该课堂
classids.push(classId)
bitrate = bitrate * 1024 // 转换 * 1024
new MediaCreat().recordingCreat(classId, siteId,classUrl,duration,width,height,frameRate,bitrate)
res.send({ code: "0" });
}else{
res.send({ code: "2", message: "重复请求课堂号" });
}
} else {
res.send({ code: "1", message: "缺少参数" });
}
})
module.exports = router;
... ...
var express = require('express');
var router = express.Router();
const { exec } = require('child_process');
const fs = require("fs");
const axios = require('axios');
const method = require("../config/method")
const { dayTimeYMD } = method
let classids = []
/**
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() {
}
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
recordingCreat(id,siteId,classUrl,duration,width,height,frameRate,bitrate) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = null
let timeDir = dayTimeYMD().ymd
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + timeDir
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
this.wrieLog("files:" + files)
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
return
}
// if(!classUrl){
// classUrl = `${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}"`
// }
// if(!duration){
// duration = BACKMEDIACONFIG.d
// }
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${classUrl}" -d=${duration} -s=${BACKMEDIACONFIG.s} -k=${BACKMEDIACONFIG.k} -w=${width} -h=${height} -fa=${frameRate} -vb=${bitrate}`
this.wrieLog("测试全地址"+url)
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
// 删除已存元素
classids.splice(classids.findIndex(item => item === id),1)
return
}
let files = fs.readdirSync(ymdDir);
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog(" 录制完成 课堂号:" + id)
// 删除已存元素
classids.splice(classids.findIndex(item => item === id),1)
}
})
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/realTimeConfig.json")
return String(buffer)
}
}
/**
* {
* "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
* }
*/
router.post('/recording', function (req, res, next) {
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
/**
* classId:课堂号
* siteId:机构编码
* url:课堂地址
* duration:录制时长
* width height 录制视频宽高
* frameRate 帧率
* bitrate 码率
*/
let { classId,siteId,url:classUrl,duration,width,height,frameRate,bitrate } = req.body
if (classId && siteId && classUrl && duration && width && height && frameRate && bitrate) {
if(!Number.isInteger(classId) || !Number.isInteger(duration) || !Number.isInteger(width) || !Number.isInteger(height) || !Number.isInteger(frameRate) || !Number.isInteger(bitrate)){
res.send({ code: "1", message: "参数类型错误" });
return
}
let maxTime = 10*60*60*1000
if(duration < 0 || duration > maxTime){
res.send({ code: "1", message: "参数范围错误" });
return
}
// 避免多次重复课堂号请求
if(!classids.includes(classId)){
// 没有正在录制的该课堂
classids.push(classId)
bitrate = bitrate * 1024 // 转换 * 1024
new MediaCreat().recordingCreat(classId, siteId,classUrl,duration,width,height,frameRate,bitrate)
res.send({ code: "0" });
}else{
res.send({ code: "2", message: "重复请求课堂号" });
}
} else {
res.send({ code: "1", message: "缺少参数" });
}
})
module.exports = router;
... ...
var express = require('express');
var router = express.Router();
const { spawn } = require('child_process');
const express = require('express');
const router = express.Router();
const { spawn, exec } = require('child_process');
const fs = require("fs");
var path = require('path')
const OSS = require('ali-oss');
require('dotenv').config(); // 加载环境变量
const method = require("../config/method")
const config = require("../config/config")
// const { GETCLASSURL, GETCLASSURLPARAMETER, PROJECTCATALOG, PROJECTWINCATALOG, BACKMEDIACONFIG } = config
const { YesterdayTime, getRequestClassIds,dayTimeYMD } = method
const { YesterdayTime, getRequestClassIds, dayTimeYMD } = method
const { startTime, endTime, ymd } = YesterdayTime()
let siteIds = []
let classid = []
let classidPost = []
let parentData = {}
var classobj = {};
let className = ""
let yesterday = "" // get写入课堂的时间
// spawn("export DISPLAY=:7", { shell: true})
/**
*
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() { }
// 取出所有数据
async allData() {
let fileConfig = await new MediaCreat().getConfigFileJson()
if(!fileConfig) return false
className = siteIds.shift()
const { GETCLASSURL,GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
let page = 1
if (className) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, page)
parentData[result.data.data.siteId] = new Set()
for (let j = 0; j < result.data.data.list.length; j++) {
classid.push(result.data.data.list[j])
parentData[result.data.data.siteId].add(result.data.data.list[j]['classId'])
}
const { siteId, list, totalPage } = result.data.data
for (let i = page += 1; i <= totalPage; i++) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, i)
for (let j = 0; j < result.data.data.list.length; j++) {
classid.push(result.data.data.list[j])
parentData[result.data.data.siteId].add(result.data.data.list[j]['classId'])
}
}
parentData[result.data.data.siteId] = Array.from(parentData[result.data.data.siteId])
if (siteIds.length) {
return await new MediaCreat().allData()
}
this.wrieLog("去重前的classId:------>" + JSON.stringify(classid))
this.wrieLog("httpData:------>" + JSON.stringify(result.data))
return true
} else {
return false
constructor() {
}
}
wrieLog(text){
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile,new Date().toLocaleString() + " " +text+'\r\n');
}
async mediaCreat(id, siteId) {
let fileConfig = await new MediaCreat().getConfigFileJson()
if(!fileConfig) return false
const { BACKMEDIACONFIG,PROJECTWINCATALOG,PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + ymd
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
// 取出所有数据
async allData() {
const { startTime, endTime } = YesterdayTime()
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
className = siteIds.shift()
const { GETCLASSURL, GETCLASSURLPARAMETER, classLastNumber } = JSON.parse(fileConfig)
let page = 1
if (className) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, page)
// parentData[result.data.data.siteId] = new Set()
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)){
classid.push(item)
// parentData[result.data.data.siteId].add(classId)
}
}
const { siteId, list, totalPage } = result.data.data
for (let i = page += 1; i <= totalPage; i++) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, i)
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)) {
classid.push(item)
// parentData[result.data.data.siteId].add(classId)
}
}
}
// parentData[result.data.data.siteId] = Array.from(parentData[result.data.data.siteId])
if (siteIds.length) {
return await new MediaCreat().allData()
}
this.wrieLog("去重前的classId:------>" + JSON.stringify(classid))
this.wrieLog("httpData:------>" + JSON.stringify(result.data))
return true
} else {
return false
}
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
let url = `web_capture_c -o=../media/${siteId}/${ymd}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
var workerProcess = spawn(url, { cwd: PROJECTWINCATALOG, shell: true })
// workerProcess.stdout.on('data', async function (data) {
// });
workerProcess.on('close', async (code) => {
let files = fs.readdirSync(ymdDir);
if (files.indexOf(id + ".mp4") == -1) {
//当前课堂没有写入到文件夹,进入重录
new MediaCreat().mediaCreat(id, siteId)
return false
} else {
if (parentData[siteId].indexOf(id.toString()) != -1) {
parentData[siteId].splice(parentData[siteId].indexOf(id.toString()), 1)
recordingCreat(id, siteId, type) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = null
if (type == 'post') {
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + dayTimeYMD().ymd
} else {
// get 的目录创建为上一天日期
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + yesterday
}
if (parentData[siteId].length == 0) {
// //全部录制完毕
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (classid.length) {
let shiftData = classid.shift()
new MediaCreat().mediaCreat(shiftData['classId'], shiftData['siteId'])
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
}
});
}
async recordingCreat(id, siteId) {
let fileConfig = await new MediaCreat().getConfigFileJson()
if(!fileConfig) return false
const { BACKMEDIACONFIG,PROJECTWINCATALOG,PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let recordingDir = mediaDir + "recording/"
let classDir = recordingDir + siteId +"/"
let dateDir = classDir + dayTimeYMD().ymd
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(recordingDir)) {
fs.mkdirSync(recordingDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(dateDir)) {
fs.mkdirSync(dateDir);
}
let url = `web_capture_c -o=../media/recording/${siteId}/${dayTimeYMD().ymd}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
var workerProcess = spawn(url, { cwd: PROJECTWINCATALOG, shell: true })
// workerProcess.stdout.on('data', async function (data) {
// });
workerProcess.on('close', async (code) =>{
let files = fs.readdirSync(dateDir);
if (files.indexOf(id + ".mp4") == -1) {
//当前课堂没有写入到文件夹,进入重录
new MediaCreat().recordingCreat(id, siteId)
return false
} else {
if (parentData[siteId].indexOf(id.toString()) != -1) {
parentData[siteId].splice(parentData[siteId].indexOf(id.toString()), 1)
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
if (parentData[siteId].length == 0) {
// //全部录制完毕
this.wrieLog("录制结束:------>")
fs.writeFile(dateDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
this.wrieLog("ymdDir" + ymdDir)
this.wrieLog("files:" + files)
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
if (type == 'post') {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
} else {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
}
});
}
if (classid.length) {
let shiftData = classid.shift()
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'])
return
}
}
});
}
async getConfigFileJson(){
const buffer= fs.readFileSync(process.cwd()+"/config/config.json")
return String(buffer)
}
// 目前url是linux的写法 win系统不支持
// export DISPLAY=:7
// let url = `${path.resolve(__dirname, PROJECTWINCATALOG+"/web_capture_c")} -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
// console.log("url", url)
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}&language=zh-cn" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
this.wrieLog(" 启动url " + url)
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
return
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
if (files.indexOf(id + ".mp4") == -1) {
this.wrieLog(" 课堂录制未发现该" + id + "课堂号")
} else {
if (type == 'get') {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
} else {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
}
}
})
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/config.json")
return String(buffer)
}
}
router.get('/', async function (req, res, next) {
new MediaCreat().wrieLog("录制开始:------>")
let fileConfig = await new MediaCreat().getConfigFileJson()
if(!fileConfig) return false
const {GETCLASSURLPARAMETER} = JSON.parse(fileConfig)
siteIds = GETCLASSURLPARAMETER.siteId
let result = await new MediaCreat().allData()
if (result) {
// 去重
classobj = {}
classid = classid.reduce(function (item, next) {
classobj[next.classId] ? '' : classobj[next.classId] = true && item.push(next);
return item;
}, []);
// 写入log
new MediaCreat().wrieLog("去重后的classid:------>" + JSON.stringify(classid))
if (classid.length) {
for (let i = 0; i < GETCLASSURLPARAMETER.maxMedia; i++) {
let shiftData = classid.shift()
if (shiftData) {
new MediaCreat().mediaCreat(shiftData['classId'], shiftData['siteId'])
router.get('/recording', async function (req, res, next) {
if (classid.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classid });
return
}
new MediaCreat().wrieLog("脚本录制开始:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
const { GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
siteIds = GETCLASSURLPARAMETER.siteId
if (siteIds.length == 0) {
new MediaCreat().wrieLog("脚本录制,未配置siteId:------>" + siteIds)
res.send({ code: "1", message: "未配置siteId", data: siteIds });
return
}
let result = await new MediaCreat().allData()
if (result) {
// 去重
classobj = {}
classid = classid.reduce(function (item, next) {
classobj[next.classId] ? '' : classobj[next.classId] = true && item.push(next);
return item;
}, []);
// 写入log
new MediaCreat().wrieLog("去重后的classid:------>" + JSON.stringify(classid))
if (classid.length) {
for (let i = 0; i < GETCLASSURLPARAMETER.maxMedia; i++) {
let shiftData = classid.shift()
if (shiftData) {
yesterday = YesterdayTime().ymd
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'get')
} else {
return false
}
}
res.send({ code: "0" });
} else {
return false
res.send({ code: "1", message: "无录制数据" });
}
}
res.send({ code: "0" });
}else{
res.send({ code: "1" ,message:"无录制数据"});
} else {
res.send({ code: "1", message: "无录制数据" });
}
}
});
/**
... ... @@ -210,33 +238,103 @@ router.get('/', async function (req, res, next) {
* }
*/
router.post('/recording', async function (req, res, next) {
new MediaCreat().wrieLog("录制开始:------>")
let fileConfig = await new MediaCreat().getConfigFileJson()
if(!fileConfig) return false
const { classId } = req.body
if(classId && classId.length){
classid = classId
const { PROJECTCATALOG,GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
for(let i=0;i<classId.length;i++){
if(!Array.isArray(parentData[classId[i].siteId])){
parentData[classId[i].siteId] = []
}
parentData[classId[i].siteId].push(classId[i].classId)
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
let { classId, maxMedia } = req.body
if (classidPost.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classidPost });
return
}
for(let i=0;i<GETCLASSURLPARAMETER.maxMedia;i++){
let shiftData = classid.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'])
} else {
return false
}
if (classId && classId.length) {
classidPost = classId
if (!maxMedia || maxMedia == undefined) {
maxMedia = 1
}
for (let i = 0; i < maxMedia; i++) {
let shiftData = classidPost.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'post')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
res.send({ code: "0" });
}else{
res.send({ code: "1" ,message:"无录制数据"});
}
})
// 判断该视频文件是否存在
router.post('/fileExists', async (req, res) => {
const { siteId, classId, classStartTime } = req.body;
// 检查输入参数
if (!siteId) {
return res.status(400).send({ code: 2, message: "机构编码无效" });
}
if (!classId) {
return res.status(400).send({ code: 3, message: "课堂号无效" });
}
try {
// 检查环境变量是否设置
if (!process.env.ALIBABA_CLOUD_ACCESS_KEY_ID || !process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET) {
throw new Error('Environment variables are not set correctly.');
}
// 创建OSS客户端实例
const client = new OSS({
region: 'oss-cn-beijing',
accessKeyId: process.env.ALIBABA_CLOUD_ACCESS_KEY_ID,
accessKeySecret: process.env.ALIBABA_CLOUD_ACCESS_KEY_SECRET,
authorizationV4: true,
bucket: 'xdymp4'
});
// 构建文件前缀
let prefix = '';
if (classStartTime) {
prefix = `oss/${siteId}/${classStartTime}/${classId}.mp4`;
} else {
// 如果没有提供classStartTime,默认返回文件未生成
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${classId}&channels=2&playRecord=1#/`;
return res.send({ code: 1, message: "文件未生成", classUrl });
}
// 使用 await 处理异步操作
const result = await client.list({ prefix });
console.log('OSS list result:', JSON.stringify(result, null, 2)); // 日志记录详细结果
// 检查是否有匹配的文件
let isVideo = false;
let url = "";
if (result.res.status === 200 && result.objects && result.objects.length > 0) {
for (let item of result.objects) {
// 更精确的匹配逻辑,确保找到的是目标文件
if (item.name === `${prefix}`) {
isVideo = true;
url = item.name;
break;
}
}
}
// 根据结果发送响应
if (!isVideo) {
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${classId}&channels=2&playRecord=1#/`;
res.send({ code: 1, message: "文件未生成", classUrl });
} else {
let classUrl = `https://xdymp4.xuedianyun.com/${url}`;
res.send({ code: 0, message: "文件已生成", classUrl });
}
} catch (err) {
console.error('Error checking file existence:', err);
res.status(500).send({ code: -1, message: "服务器内部错误", error: err.message });
}
});
module.exports = router;
module.exports = router
... ...
var express = require('express');
var router = express.Router();
const { spawn, exec } = require('child_process');
const fs = require("fs");
var path = require('path')
var ObsClient = require('esdk-obs-nodejs');
const method = require("../config/method")
const config = require("../config/config")
// const { GETCLASSURL, GETCLASSURLPARAMETER, PROJECTCATALOG, PROJECTWINCATALOG, BACKMEDIACONFIG } = config
const { YesterdayTime, getRequestClassIds, dayTimeYMD } = method
let siteIds = []
let classid = []
let classidPost = []
let parentData = {}
var classobj = {};
let className = ""
// spawn("export DISPLAY=:7", { shell: true})
/**
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() {
}
// 取出所有数据
async allData() {
const { startTime, endTime } = YesterdayTime()
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
className = siteIds.shift()
const { GETCLASSURL, GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
let page = 1
if (className) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, page)
parentData[result.data.data.siteId] = new Set()
for (let j = 0; j < result.data.data.list.length; j++) {
classid.push(result.data.data.list[j])
parentData[result.data.data.siteId].add(result.data.data.list[j]['classId'])
}
const { siteId, list, totalPage } = result.data.data
for (let i = page += 1; i <= totalPage; i++) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, i)
for (let j = 0; j < result.data.data.list.length; j++) {
classid.push(result.data.data.list[j])
parentData[result.data.data.siteId].add(result.data.data.list[j]['classId'])
}
}
parentData[result.data.data.siteId] = Array.from(parentData[result.data.data.siteId])
if (siteIds.length) {
return await new MediaCreat().allData()
}
this.wrieLog("去重前的classId:------>" + JSON.stringify(classid))
this.wrieLog("httpData:------>" + JSON.stringify(result.data))
return true
} else {
return false
}
}
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
recordingCreat(id, siteId, type) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = null
if (type == 'post') {
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + dayTimeYMD().ymd
} else {
// get 的目录创建为上一天日期
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + YesterdayTime().ymd
}
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
this.wrieLog("files:" + files)
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
if (type == 'post') {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
} else {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
}
return
}
// 目前url是linux的写法 win系统不支持
// export DISPLAY=:7
// let url = `${path.resolve(__dirname, PROJECTWINCATALOG+"/web_capture_c")} -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
// console.log("url", url)
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}&language=zh-cn" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h} -vb=999999999999`
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
return
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
if (files.indexOf(id + ".mp4") == -1) {
this.wrieLog(" 课堂录制未发现该" + id + "课堂号")
} else {
if (type == 'get') {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
} else {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
}
}
})
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/config.json")
return String(buffer)
}
}
router.get('/recording', async function (req, res, next) {
if (classid.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classid });
return
}
new MediaCreat().wrieLog("脚本录制开始:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
const { GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
siteIds = GETCLASSURLPARAMETER.siteId
if (siteIds.length == 0) {
new MediaCreat().wrieLog("脚本录制,未配置siteId:------>" + siteIds)
res.send({ code: "1", message: "未配置siteId", data: siteIds });
return
}
let result = await new MediaCreat().allData()
if (result) {
// 去重
classobj = {}
classid = classid.reduce(function (item, next) {
classobj[next.classId] ? '' : classobj[next.classId] = true && item.push(next);
return item;
}, []);
// 写入log
new MediaCreat().wrieLog("去重后的classid:------>" + JSON.stringify(classid))
if (classid.length) {
for (let i = 0; i < GETCLASSURLPARAMETER.maxMedia; i++) {
let shiftData = classid.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'get')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
} else {
res.send({ code: "1", message: "无录制数据" });
}
});
/**
* {
* "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
* }
*/
router.post('/recording', async function (req, res, next) {
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
let { classId, maxMedia } = req.body
if (classidPost.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classidPost });
return
}
if (classId && classId.length) {
classidPost = classId
if (!maxMedia || maxMedia == undefined) {
maxMedia = 1
}
for (let i = 0; i < maxMedia; i++) {
let shiftData = classidPost.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'post')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
})
// 判断该视频文件是否存在
router.post('/fileExists', async function (req, res, next) {
const body = req.body
if(!body.siteId) {
res.send({ code: 2,message:"机构编码无效" });
return
}
if(!body.classId) {
res.send({ code: 3,message:"课堂号无效" });
return
}
// 创建ObsClient实例
var obsClient = new ObsClient({
access_key_id: 'FY27OD11ZJVC385AOTW9',
secret_access_key: 'ZqnfRjaseCtuRbE79GvqkPiYUdT83ZbB0oU7fBo3',
server : 'obs.cn-north-4.myhuaweicloud.com'
});
let isVideo = false
let url = ""
obsClient.listObjects({
Bucket : 'xdymp4'
}, (err, result) => {
if(err){
console.error('Error-->' + err);
}else{
if(result.CommonMsg.Status == 200){
for(let i=0;i<result.InterfaceResult.Contents.length;i++){
let item = result.InterfaceResult.Contents[i]
if(item.Key && item.Key.indexOf(body.classId) > -1){
isVideo = true
url = item.Key
break
}
}
}
}
if(!isVideo){
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${body.classId}&channels=2&playRecord=1#/`
res.send({ code: 1,message:"文件未生成",classUrl });
}else{
let classUrl = `https://xdymp4.xuedianyun.com/${url}`
res.send({ code: 0,message:"文件已生成",classUrl });
}
// 关闭obsClient
obsClient.close();
});
})
module.exports = router;
... ...
var express = require('express');
var router = express.Router();
const { spawn, exec } = require('child_process');
const fs = require("fs");
var path = require('path')
var ObsClient = require('esdk-obs-nodejs');
const method = require("../config/method")
const config = require("../config/config")
// const { GETCLASSURL, GETCLASSURLPARAMETER, PROJECTCATALOG, PROJECTWINCATALOG, BACKMEDIACONFIG } = config
const { YesterdayTime, getRequestClassIds, dayTimeYMD } = method
let siteIds = []
let classid = []
let classidPost = []
let parentData = {}
var classobj = {};
let className = ""
let yesterday = "" // get写入课堂的时间
// spawn("export DISPLAY=:7", { shell: true})
/**
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() {
}
// 取出所有数据
async allData() {
const { startTime, endTime } = YesterdayTime()
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
className = siteIds.shift()
const { GETCLASSURL, GETCLASSURLPARAMETER, classLastNumber } = JSON.parse(fileConfig)
let page = 1
if (className) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, page)
// parentData[result.data.data.siteId] = new Set()
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)){
classid.push(item)
// parentData[result.data.data.siteId].add(classId)
}
}
const { siteId, list, totalPage } = result.data.data
for (let i = page += 1; i <= totalPage; i++) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, i)
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)) {
classid.push(item)
// parentData[result.data.data.siteId].add(classId)
}
}
}
// parentData[result.data.data.siteId] = Array.from(parentData[result.data.data.siteId])
if (siteIds.length) {
return await new MediaCreat().allData()
}
this.wrieLog("去重前的classId:------>" + JSON.stringify(classid))
this.wrieLog("httpData:------>" + JSON.stringify(result.data))
return true
} else {
return false
}
}
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
recordingCreat(id, siteId, type) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = null
if (type == 'post') {
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + dayTimeYMD().ymd
} else {
// get 的目录创建为上一天日期
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + yesterday
}
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
this.wrieLog("ymdDir" + ymdDir)
this.wrieLog("files:" + files)
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
if (type == 'post') {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
} else {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
}
return
}
// 目前url是linux的写法 win系统不支持
// export DISPLAY=:7
// let url = `${path.resolve(__dirname, PROJECTWINCATALOG+"/web_capture_c")} -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
// console.log("url", url)
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}&language=zh-tw" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
this.wrieLog(" 启动url " + url)
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
return
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
if (files.indexOf(id + ".mp4") == -1) {
this.wrieLog(" 课堂录制未发现该" + id + "课堂号")
} else {
if (type == 'get') {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
} else {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
}
}
})
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/config.json")
return String(buffer)
}
}
router.get('/recording', async function (req, res, next) {
if (classid.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classid });
return
}
new MediaCreat().wrieLog("脚本录制开始:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
const { GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
siteIds = GETCLASSURLPARAMETER.siteId
if (siteIds.length == 0) {
new MediaCreat().wrieLog("脚本录制,未配置siteId:------>" + siteIds)
res.send({ code: "1", message: "未配置siteId", data: siteIds });
return
}
let result = await new MediaCreat().allData()
if (result) {
// 去重
classobj = {}
classid = classid.reduce(function (item, next) {
classobj[next.classId] ? '' : classobj[next.classId] = true && item.push(next);
return item;
}, []);
// 写入log
new MediaCreat().wrieLog("去重后的classid:------>" + JSON.stringify(classid))
if (classid.length) {
for (let i = 0; i < GETCLASSURLPARAMETER.maxMedia; i++) {
let shiftData = classid.shift()
if (shiftData) {
yesterday = YesterdayTime().ymd
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'get')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
} else {
res.send({ code: "1", message: "无录制数据" });
}
});
/**
* {
* "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
* }
*/
router.post('/recording', async function (req, res, next) {
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
let { classId, maxMedia } = req.body
if (classidPost.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classidPost });
return
}
if (classId && classId.length) {
classidPost = classId
if (!maxMedia || maxMedia == undefined) {
maxMedia = 1
}
for (let i = 0; i < maxMedia; i++) {
let shiftData = classidPost.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'post')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
})
// 判断该视频文件是否存在
router.post('/fileExists', async function (req, res, next) {
const body = req.body
if (!body.siteId) {
res.send({code: 2, message: "机构编码无效"});
return
}
if (!body.classId) {
res.send({code: 3, message: "课堂号无效"});
return
}
// if(!body.classStartTime) {
// res.send({ code: 4,message:"时间不存在" });
// return
// }
// 创建ObsClient实例
var obsClient = new ObsClient({
access_key_id: 'LHFQDCSI4AQVDMEBI5TQ',
secret_access_key: '6iPZ2RM41cAFUvAmTSrjRS4vgjAP0bnwM9kiCXIk',
server: 'obs.cn-north-4.myhuaweicloud.com'
});
let isVideo = false
let url = ""
let Prefix = ""
if (body.classStartTime) {
Prefix = `oss/${body.siteId}/${body.classStartTime}/${body.classId}.mp4`
obsClient.listObjects({
Bucket: 'mp4record',
Prefix: Prefix,
// MaxKeys:1
}, (err, result) => {
if (err) {
console.error('Error-->' + err);
} else {
if (result.CommonMsg.Status == 200) {
let content = result.InterfaceResult.Contents
if (content && content.length) {
if (content[0].Key) {
isVideo = true
url = content[0].Key
}
}
// for(let i=0;i<result.InterfaceResult.Contents.length;i++){
// let item = result.InterfaceResult.Contents[i]
// if(item.Key && item.Key.indexOf(body.classId) > -1){
// isVideo = true
// url = item.Key
// break
// }
// }
}
}
if (!isVideo) {
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${body.classId}&channels=2&playRecord=1#/`
res.send({code: 1, message: "文件未生成", classUrl});
} else {
let classUrl = `https://xdymp4.xuedianyun.com/${url}`
res.send({code: 0, message: "文件已生成", classUrl});
}
// 关闭obsClient
obsClient.close();
});
}else{
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${body.classId}&channels=2&playRecord=1#/`
res.send({code: 1, message: "文件未生成", classUrl});
}
})
module.exports = router;
... ...
var express = require('express');
var router = express.Router();
const { spawn, exec } = require('child_process');
const fs = require("fs");
var path = require('path')
var ObsClient = require('esdk-obs-nodejs');
const method = require("../config/method")
const config = require("../config/config")
// const { GETCLASSURL, GETCLASSURLPARAMETER, PROJECTCATALOG, PROJECTWINCATALOG, BACKMEDIACONFIG } = config
const { YesterdayTime, getRequestClassIds, dayTimeYMD } = method
let siteIds = []
let classid = []
let classidPost = []
let parentData = {}
var classobj = {};
let className = ""
let yesterday = "" // get写入课堂的时间
// spawn("export DISPLAY=:7", { shell: true})
/**
*
* @param {*} id 课堂id
*/
class MediaCreat {
constructor() {
}
// 取出所有数据
async allData() {
const { startTime, endTime } = YesterdayTime()
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
className = siteIds.shift()
const { GETCLASSURL, GETCLASSURLPARAMETER,classLastNumber } = JSON.parse(fileConfig)
let page = 1
if (className) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, page)
//parentData[result.data.data.siteId] = new Set()
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)){
classid.push(item)
//parentData[result.data.data.siteId].add(classId)
}
}
const { siteId, list, totalPage } = result.data.data
for (let i = page += 1; i <= totalPage; i++) {
let result = await getRequestClassIds(GETCLASSURL, className, GETCLASSURLPARAMETER.key, startTime, endTime, i)
let resultList = result.data.data.list
for (let j = 0; j < resultList.length; j++) {
let item = resultList[j]
let classId = item['classId']
let number = classId.substr(classId.length - 1, 1)
if (classLastNumber.includes(number)) {
classid.push(item)
// parentData[result.data.data.siteId].add(classId)
}
}
}
// parentData[result.data.data.siteId] = Array.from(parentData[result.data.data.siteId])
if (siteIds.length) {
return await new MediaCreat().allData()
}
this.wrieLog("去重前的classId:------>" + JSON.stringify(classid))
this.wrieLog("httpData:------>" + JSON.stringify(result.data))
return true
} else {
return false
}
}
wrieLog(text) {
// 写入log
let logFile = `./log/${dayTimeYMD().ymd}.txt`
fs.appendFileSync(logFile, new Date().toLocaleString() + " " + text + '\r\n');
}
recordingCreat(id, siteId, type) {
this.wrieLog(" 课堂录制开始:------>" + id)
let fileConfig = this.getConfigFileJson()
if (!fileConfig) return false
const { BACKMEDIACONFIG, PROJECTWINCATALOG, PROJECTCATALOG } = JSON.parse(fileConfig)
let mediaDir = PROJECTCATALOG + "/media/"
let classDir = PROJECTCATALOG + "/media/" + siteId
let ymdDir = null
if (type == 'post') {
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + dayTimeYMD().ymd
} else {
// get 的目录创建为上一天日期
ymdDir = PROJECTCATALOG + "/media/" + siteId + "/" + yesterday
}
if (!fs.existsSync(mediaDir)) {
fs.mkdirSync(mediaDir);
}
if (!fs.existsSync(classDir)) {
fs.mkdirSync(classDir);
}
if (!fs.existsSync(ymdDir)) {
fs.mkdirSync(ymdDir);
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
this.wrieLog("files:" + files)
if (files.indexOf(id + ".mp4") != -1) {
this.wrieLog("已存在:" + id + "课堂号,停止继续录制")
if (type == 'post') {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
} else {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
}
}
return
}
// 目前url是linux的写法 win系统不支持
// export DISPLAY=:7
// let url = `${path.resolve(__dirname, PROJECTWINCATALOG+"/web_capture_c")} -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
// console.log("url", url)
let url = `${PROJECTWINCATALOG}/web_capture_c -o=${ymdDir}/${id}.mp4 -u="${BACKMEDIACONFIG.url}?classId=${id}&recordMp4=${BACKMEDIACONFIG.recordMp4}&userId=${BACKMEDIACONFIG.userId}&userName=${BACKMEDIACONFIG.userName}&userRole=${BACKMEDIACONFIG.userRole}&portalIP=${BACKMEDIACONFIG.portalIP}&portalPort=${BACKMEDIACONFIG.portalPort}&channels=${BACKMEDIACONFIG.channels}&playRecord=${BACKMEDIACONFIG.playRecord}&language=zh-cn" -d=${BACKMEDIACONFIG.d} -s=${BACKMEDIACONFIG.s} -fa=${BACKMEDIACONFIG.fa} -k=${BACKMEDIACONFIG.k} -w=${BACKMEDIACONFIG.w} -h=${BACKMEDIACONFIG.h}`
exec(url, { maxBuffer: 1073741824 }, (err, stdout, stderr) => {
if (err != null) {
this.wrieLog(" 错误" + id + ":" + err)
this.wrieLog(" 错误 stdout" + id + ":" + stdout)
this.wrieLog(" 错误 stderr" + id + ":" + stderr)
return
}
let files = fs.readdirSync(ymdDir);
// let interValGetFile = setInterval(()=>{
if (files.indexOf(id + ".mp4") == -1) {
this.wrieLog(" 课堂录制未发现该" + id + "课堂号")
} else {
if (type == 'get') {
if (classid.length) {
let shiftData = classid.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
} else {
if (classidPost.length) {
let shiftData = classidPost.shift()
this.wrieLog(" 录制下一节课 课堂号:" + shiftData['classId'])
this.recordingCreat(shiftData['classId'], shiftData['siteId'], type)
} else {
this.wrieLog("录制结束:------>")
fs.writeFile(ymdDir + "/download.json", `{ "code": "0", "success": "ok"}`, function (err) {
if (err) {
console.log(err);
}
});
}
}
}
})
}
getConfigFileJson() {
const buffer = fs.readFileSync(process.cwd() + "/config/config.json")
return String(buffer)
}
}
router.get('/recording', async function (req, res, next) {
if (classid.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classid });
return
}
new MediaCreat().wrieLog("脚本录制开始:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
const { GETCLASSURLPARAMETER } = JSON.parse(fileConfig)
siteIds = GETCLASSURLPARAMETER.siteId
if (siteIds.length == 0) {
new MediaCreat().wrieLog("脚本录制,未配置siteId:------>" + siteIds)
res.send({ code: "1", message: "未配置siteId", data: siteIds });
return
}
let result = await new MediaCreat().allData()
if (result) {
// 去重
classobj = {}
classid = classid.reduce(function (item, next) {
classobj[next.classId] ? '' : classobj[next.classId] = true && item.push(next);
return item;
}, []);
// 写入log
new MediaCreat().wrieLog("去重后的classid:------>" + JSON.stringify(classid))
if (classid.length) {
for (let i = 0; i < GETCLASSURLPARAMETER.maxMedia; i++) {
let shiftData = classid.shift()
if (shiftData) {
yesterday = YesterdayTime().ymd
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'get')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
} else {
res.send({ code: "1", message: "无录制数据" });
}
});
/**
* {
* "classId":[{ classId: '389675110', siteId: 'kuaikuenglish' }]
* }
*/
router.post('/recording', async function (req, res, next) {
new MediaCreat().wrieLog("录制启动:------>")
let fileConfig = new MediaCreat().getConfigFileJson()
if (!fileConfig) return false
let { classId, maxMedia } = req.body
if (classidPost.length > 0) {
// 有正在录制中的课堂,禁止重复
res.send({ code: "1", message: "有正在录制中的课堂", data: classidPost });
return
}
if (classId && classId.length) {
classidPost = classId
if (!maxMedia || maxMedia == undefined) {
maxMedia = 1
}
for (let i = 0; i < maxMedia; i++) {
let shiftData = classidPost.shift()
if (shiftData) {
new MediaCreat().recordingCreat(shiftData['classId'], shiftData['siteId'], 'post')
} else {
return false
}
}
res.send({ code: "0" });
} else {
res.send({ code: "1", message: "无录制数据" });
}
})
// 判断该视频文件是否存在
router.post('/fileExists', async function (req, res, next) {
const body = req.body
if(!body.siteId) {
res.send({ code: 2,message:"机构编码无效" });
return
}
if(!body.classId) {
res.send({ code: 3,message:"课堂号无效" });
return
}
// 创建ObsClient实例
var obsClient = new ObsClient({
access_key_id: 'FY27OD11ZJVC385AOTW9',
secret_access_key: 'ZqnfRjaseCtuRbE79GvqkPiYUdT83ZbB0oU7fBo3',
server : 'obs.cn-north-4.myhuaweicloud.com'
});
let isVideo = false
let url = ""
obsClient.listObjects({
Bucket : 'xdymp4'
}, (err, result) => {
if(err){
console.error('Error-->' + err);
}else{
if(result.CommonMsg.Status == 200){
for(let i=0;i<result.InterfaceResult.Contents.length;i++){
let item = result.InterfaceResult.Contents[i]
if(item.Key && item.Key.indexOf(body.classId) > -1){
isVideo = true
url = item.Key
break
}
}
}
}
if(!isVideo){
let classUrl = `https://pclive.xuedianyun.com/pcBase/pclive2/release/index.html?portalIP=saas.xuedianyun.com&portalPort=80&classId=${body.classId}&channels=2&playRecord=1#/`
res.send({ code: 1,message:"文件未生成",classUrl });
}else{
let classUrl = `https://xdymp4.xuedianyun.com/${url}`
res.send({ code: 0,message:"文件已生成",classUrl });
}
// 关闭obsClient
obsClient.close();
});
})
module.exports = router;
... ...