Shinobi/libs/basic/utils.js

287 lines
10 KiB
JavaScript

const fs = require('fs');
const fsP = require('fs').promises;
const path = require('path');
const moment = require('moment');
const fetch = require('node-fetch');
const FormData = require('form-data');
const { AbortController } = require('node-abort-controller')
const DigestFetch = require('digest-fetch')
module.exports = (processCwd,config) => {
const parseJSON = (string) => {
var parsed
try{
parsed = JSON.parse(string)
}catch(err){
}
if(!parsed)parsed = string
return parsed
}
const stringJSON = (json) => {
try{
if(json instanceof Object){
json = JSON.stringify(json)
}
}catch(err){
}
return json
}
const stringContains = (find,string,toLowerCase) => {
var newString = string + ''
if(toLowerCase)newString = newString.toLowerCase()
return newString.indexOf(find) > -1
}
function getFileDirectory(filePath){
const fileParts = filePath.split('/')
fileParts.pop();
return fileParts.join('/') + '/';
}
const checkCorrectPathEnding = (x) => {
var length=x.length
if(x.charAt(length-1)!=='/'){
x=x+'/'
}
return x.replace('__DIR__',processCwd)
}
const mergeDeep = function(...objects) {
const isObject = obj => obj && typeof obj === 'object';
return objects.reduce((prev, obj) => {
Object.keys(obj).forEach(key => {
const pVal = prev[key];
const oVal = obj[key];
if (Array.isArray(pVal) && Array.isArray(oVal)) {
prev[key] = pVal.concat(...oVal);
}
else if (isObject(pVal) && isObject(oVal)) {
prev[key] = mergeDeep(pVal, oVal);
}
else {
prev[key] = oVal;
}
});
return prev;
}, {});
}
const nameToTime = (x) => {
x = x.split('.')[0].split('T')
if(x[1])x[1] = x[1].replace(/-/g,':')
x = x.join(' ')
return x
}
const generateRandomId = (x) => {
if(!x){x=10};var t = "";var p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < x; i++ )
t += p.charAt(Math.floor(Math.random() * p.length));
return t;
}
const utcToLocal = (time) => {
return moment.utc(time).utcOffset(s.utcOffset).format()
}
const localToUtc = (time) => {
return moment(time).utc()
}
const formattedTime = (e,x) => {
if(!e){e=new Date};if(!x){x='YYYY-MM-DDTHH-mm-ss'};
return moment(e).format(x);
}
const fetchTimeout = (url, ms, { signal, ...options } = {}) => {
const controller = new AbortController();
const promise = fetch(url, { signal: controller.signal, ...options });
if (signal) signal.addEventListener("abort", () => controller.abort());
const timeout = setTimeout(() => controller.abort(), ms);
return promise.finally(() => clearTimeout(timeout));
}
async function fetchDownloadAndWrite(downloadUrl,outputPath,readFileAfterWrite,options){
const writeStream = fs.createWriteStream(outputPath);
const downloadBuffer = await fetch(downloadUrl,options).then((res) => res.buffer());
writeStream.write(downloadBuffer);
writeStream.end();
if(readFileAfterWrite === 1){
return fs.createReadStream(outputPath)
}else if(readFileAfterWrite === 2){
return downloadBuffer
}
return null
}
function fetchWithAuthentication(requestUrl,options,callback){
let hasDigestAuthEnabled = options.digestAuth;
let theRequester;
const hasUsernameAndPassword = options.username && typeof options.password === 'string'
const requestOptions = {
method : options.method || 'GET',
headers: {'Content-Type': 'application/json'}
}
if(requestOptions.method !== 'GET'){
if(typeof options.postData === 'object'){
requestOptions.body = JSON.stringify(options.postData)
}else if(options.postData && typeof options.postData === 'string'){
try{
JSON.parse(options.postData)
requestOptions.body = options.postData
}catch(err){
}
}
}
if(hasUsernameAndPassword && hasDigestAuthEnabled){
theRequester = (new DigestFetch(options.username, options.password)).fetch
}else if(hasUsernameAndPassword){
theRequester = (new DigestFetch(options.username, options.password, { basic: true })).fetch
}else{
theRequester = fetch
}
return theRequester(requestUrl,requestOptions)
}
const checkSubscription = (subscriptionId,callback) => {
function subscriptionFailed(){
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
console.error('This Install of Shinobi is NOT Activated')
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
s.systemLog('This Install of Shinobi is NOT Activated')
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
console.log('https://licenses.shinobi.video/subscribe')
}
if(subscriptionId && subscriptionId !== 'sub_XXXXXXXXXXXX' && !config.disableOnlineSubscriptionCheck){
var url = 'https://licenses.shinobi.video/subscribe/check?subscriptionId=' + subscriptionId
var hasSubcribed = false
fetchTimeout(url,30000,{
method: 'GET',
})
.then(response => response.text())
.then(function(body){
var json = s.parseJSON(body)
hasSubcribed = json && !!json.ok
var i;
for (i = 0; i < s.onSubscriptionCheckExtensions.length; i++) {
const extender = s.onSubscriptionCheckExtensions[i]
hasSubcribed = extender(hasSubcribed,json,subscriptionId)
}
callback(hasSubcribed)
if(hasSubcribed){
s.systemLog('This Install of Shinobi is Activated')
if(!json.expired && json.timeExpires){
s.systemLog(`This License expires on ${json.timeExpires}`)
}
}else{
subscriptionFailed()
}
}).catch((err) => {
if(err)console.log(err)
subscriptionFailed()
callback(false)
})
}else{
var i;
for (i = 0; i < s.onSubscriptionCheckExtensions.length; i++) {
const extender = s.onSubscriptionCheckExtensions[i]
hasSubcribed = extender(false,{},subscriptionId)
}
if(hasSubcribed === false){
subscriptionFailed()
}
callback(hasSubcribed)
}
}
function isEven(value) {
if (value%2 == 0)
return true;
else
return false;
}
function asyncSetTimeout(timeoutAmount) {
return new Promise((resolve,reject) => {
setTimeout(function(){
resolve()
},timeoutAmount)
})
}
function copyFile(inputFilePath,outputFilePath) {
const response = {ok: true}
return new Promise((resolve,reject) => {
function failed(err){
response.ok = false
response.err = err
resolve(response)
}
const readStream = fs.createReadStream(inputFilePath)
const writeStream = fs.createWriteStream(outputFilePath)
writeStream.on('finish', () => {
resolve(response)
})
writeStream.on('error', failed)
readStream.on('error', failed)
readStream.pipe(writeStream)
})
}
async function moveFile(inputFilePath,outputFilePath) {
try{
await fsP.rm(outputFilePath)
}catch(err){}
await copyFile(inputFilePath, outputFilePath)
await fsP.rm(inputFilePath)
}
function hmsToSeconds(str) {
var p = str.split(':'),
s = 0, m = 1;
while (p.length > 0) {
s += m * parseFloat(p.pop(), 10);
m *= 60;
}
return s;
}
function setDefaultIfUndefined(config, key, defaultValue) {
const mustDoDefault = !config.userHasSubscribed;
if (Array.isArray(defaultValue)) {
if (config[key] === undefined || mustDoDefault) {
config[key] = [...defaultValue]; // Spread operator to clone the array
}
} else {
if (config[key] === undefined || mustDoDefault) {
config[key] = defaultValue;
}
}
}
async function deleteFilesInFolder(folderPath) {
try {
const files = await fsP.readdir(folderPath);
for (const file of files) {
const filePath = path.join(folderPath, file);
await fsP.rm(filePath, { recursive: true });
}
} catch (error) {
console.error(`Error deleting files: ${error.message}`);
}
}
return {
parseJSON: parseJSON,
stringJSON: stringJSON,
stringContains: stringContains,
getFileDirectory: getFileDirectory,
checkCorrectPathEnding: checkCorrectPathEnding,
nameToTime: nameToTime,
mergeDeep: mergeDeep,
generateRandomId: generateRandomId,
utcToLocal: utcToLocal,
localToUtc: localToUtc,
formattedTime: formattedTime,
checkSubscription: checkSubscription,
isEven: isEven,
fetchTimeout: fetchTimeout,
fetchDownloadAndWrite: fetchDownloadAndWrite,
fetchWithAuthentication: fetchWithAuthentication,
asyncSetTimeout: asyncSetTimeout,
copyFile: copyFile,
hmsToSeconds,
setDefaultIfUndefined,
deleteFilesInFolder,
moveFile,
}
}