diff --git a/app.js b/app.js index edba96f8..d6ec6b93 100644 --- a/app.js +++ b/app.js @@ -26,6 +26,7 @@ const ngrok = require('ngrok'); const commandExists = require('command-exists'); const errorHandler = require('errorhandler'); const jsHelpers = require('./lib/helpers/js-helpers'); +const { UI } = require('bull-board'); /** FOR FINDING ERRANT LOGS **/ if(process.env.SHOW_LOG_LOCATION == 'true' || 2 == 1){ @@ -161,6 +162,12 @@ if(cluster.isMaster){ path: '/hiddenStatus' })); + // TODO: put this behind auth + /** bull-board queue monitor **/ + if(process.env.NODE_ENV === 'development'){ + app.use('/admin/queues', UI); + } + app.use(compression()); app.use(sass({ src: path.join(__dirname, 'public'), diff --git a/controllers/backend/uploading.js b/controllers/backend/uploading.js index f80e627f..52190718 100644 --- a/controllers/backend/uploading.js +++ b/controllers/backend/uploading.js @@ -31,6 +31,7 @@ const { b2, bucket, hostUrl } = require('../../lib/uploading/backblaze'); const ffmpegHelper = require('../../lib/uploading/ffmpeg'); const { markUploadAsComplete, + markConvertAsComplete, updateUsersUnreadSubscriptions, runTimeoutFunction, userCanUploadContentOfThisRating @@ -40,6 +41,8 @@ const backblaze = require('../../lib/uploading/backblaze'); // console.log(`SAVE AND SERVE FILES DIRECTORY: ${saveAndServeFilesDirectory}`); var resumable = require('../../lib/uploading/resumable.js')(__dirname + '/upload'); +var Queue = require('bull'); +const { setQueues } = require('bull-board'); const moderationUpdatesToDiscord = process.env.MODERATION_UPDATES_TO_DISCORD == 'true'; @@ -537,7 +540,6 @@ exports.postFileUpload = async(req, res) => { } upload.fileType = 'video'; - upload = await upload.save(); } @@ -557,17 +559,148 @@ exports.postFileUpload = async(req, res) => { uploadLogger.info('Upload marked as complete', logObject); - updateUsersUnreadSubscriptions(user); - - uploadLogger.info('Updated subscribed users subscriptions', logObject); - if(!responseSent){ responseSent = true; aboutToProcess(res, channelUrl, uniqueTag); } + + var videoQualityQueue = new Queue('Video Quality is going to convert'); + setQueues([videoQualityQueue]); + + videoQualityQueue.process(async function(job, done){ + + Upload.update({'videoQualities._id': job.data.videoQualitiesId}, {'$set': { + 'videoQualities.$.status': 'converting', + 'videoQualities.$.fileSizeInMb': 2 + }}, function(err, result){ + + if(err){ + res.send(err); + } + else { + res.send(result); + } + + }); + + job.progress(5); + + await ffmpegHelper.convertVideo({ + uploadedPath: job.data.uploadedPath, + title: job.data.title, + bitrate: job.data.bitrate, + savePath: job.data.savePath, + uniqueTag: job.data.uniqueTag, + quality: job.data.quality + }); + + job.progress(42); // TODO: set progress based on convert percentage + + Upload.update({'videoQualities._id': job.data.videoQualitiesId}, {'$set': { + 'videoQualities.$.status': 'complete', + 'videoQualities.$.fileSizeInMb': 3 + }}, function(err, result){ + + if(err){ + res.send(err); + } + // else { + // res.send(result); + // } + + }); + + // Update if all qualities are converted + // TODO: needs some cleanup + // db.uploads.findOne({}).videoQualities.every(arr=> arr.status == 'complete'); + await Upload.findOne({uniqueTag : job.data.uploadUniqueTag }) + .select('videoQualities') + .exec(async function(err, txs){ + if(txs.videoQualities.every(arr=> arr.status === 'complete')){ + await markConvertAsComplete(uniqueTag, channelUrl, user); + uploadLogger.info('Quality all qualities are converted', logObject); + updateUsersUnreadSubscriptions(user); + uploadLogger.info('Updated subscribed users subscriptions', logObject); + } + + }); + + job.progress(100); + done(); + + }); + /* + all values in Kbps (kilobits per seconds) + 2160p (4k) -> 13000 + 1440p 6000 + 1080p 3000 + 720p 2250 + 480p 500 + 360p 400 + 240p 300 + 144p 80 + + 0-80 144p + 81-299 360p + */ + // TODO: put qualities somewhere else + const qualities = [ + { name: '256 x 144p', quality: 144, bitrate: 80 }, + { name: '426 x 240p', quality: 240, bitrate: 300 }, + { name: '640 x 360p', quality: 360, bitrate: 400 }, + { name: '854 x 480p', quality: 480, bitrate: 500 }, + { name: '1280 x 720p', quality: 720, bitrate: 2250 } + ]; + // TODO: Do quality stuff + // TODO: loop quality stuff + // video will be available in original quality while this is happening in the background + // TODO: make a quality conversion counter/progress bar + for(var i = 0; i < qualities.length; i = i + 1){ + if(bitrate >= qualities[i].bitrate){ + // qualitySavePath = `${channelUrlFolder}/${uniqueTag}-${qualities[i].quality}.mp4`; + + let qualityExists = upload.videoQualities.find(o => o.quality === qualities[i].quality); + if(!qualityExists){ + + upload.videoQualities.push({ + quality: qualities[i].quality, + bitrate: qualities[i].bitrate, + fileSizeInMb: 1, + status: 'pending' // TODO: use enum here not string + }); + } + + } + } + + await upload.save(); + + for(var i = 0; i < upload.videoQualities.length; i = i + 1){ + if(bitrate >= upload.videoQualities[i].bitrate){ + if(upload.videoQualities[i].status != 'complete'){ + // TODO: this is kind of ugly lmao + qualitySavePath = `${channelUrlFolder}/${uniqueTag}-${upload.videoQualities[i].quality}.mp4`; + + videoQualityQueue.add({ + uploadId: upload._id, + videoQualitiesId: upload.videoQualities[i]._id, + uploadedPath: fileInDirectory, + title: title, + bitrate: upload.videoQualities[i].bitrate, + savePath: qualitySavePath, + uploadUniqueTag: uniqueTag, + uniqueTag: uniqueTag + '-' + upload.videoQualities[i].quality, + quality: upload.videoQualities[i].quality + }); + } + + await upload.save(); + } + + } + }); - // }); } }); } catch(err){ diff --git a/lib/uploading/ffmpeg.js b/lib/uploading/ffmpeg.js index 116830b8..4dc643af 100644 --- a/lib/uploading/ffmpeg.js +++ b/lib/uploading/ffmpeg.js @@ -79,7 +79,7 @@ function setRedisClient({ currentSeconds, uniqueTag, progress, force }){ // setRedisClient(); -function convertVideo({ uploadedPath, title, bitrate, savePath, uniqueTag }){ +function convertVideo({ uploadedPath, title, quality, bitrate, savePath, uniqueTag }){ return new Promise(function(resolve, reject) { let command; @@ -88,9 +88,12 @@ function convertVideo({ uploadedPath, title, bitrate, savePath, uniqueTag }){ command = ffmpeg(uploadedPath).videoCodec('libx264').audioCodec('aac').format('mp4') .outputOptions([ '-preset faster', '-b:v 2500k' ]); - } else { + } else if(!quality){ command = ffmpeg(uploadedPath).videoCodec('libx264').audioCodec('aac').format('mp4') + } else{ + command = ffmpeg(uploadedPath).videoCodec('libx264').audioCodec('aac').format('mp4') + .outputOptions([ '-preset faster', '-b:v ' + bitrate + 'k', '-vf scale=-2:' + quality ]); } let secondCounter = 0; diff --git a/lib/uploading/helpers.js b/lib/uploading/helpers.js index 801b6721..2b5cb6cc 100644 --- a/lib/uploading/helpers.js +++ b/lib/uploading/helpers.js @@ -18,6 +18,21 @@ async function markUploadAsComplete(uniqueTag, channelUrl, user, res){ return 'success' } +async function markConvertAsComplete(uniqueTag, channelUrl, user, res){ + // upload = await Upload.findOne({ uniqueTag }); + // upload.status = 'completed'; + + // upload.processingCompletedAt = new Date(); + + // await upload.save(); + console.log("quality converted") + + // user.uploads.push(upload._id); + // await user.save(); + + return 'success' +} + async function updateUsersUnreadSubscriptions(user){ const subscriptions = await Subscription.find({ subscribedToUser: user._id, active: true }); @@ -84,6 +99,7 @@ const bytesToGb = (bytes, decimalPlaces = 4) => { module.exports = { markUploadAsComplete, + markConvertAsComplete, updateUsersUnreadSubscriptions, runTimeoutFunction, userCanUploadContentOfThisRating, diff --git a/models/Upload.js b/models/Upload.js index dd5a0382..d86e7e0c 100644 --- a/models/Upload.js +++ b/models/Upload.js @@ -39,6 +39,15 @@ const uploadSchema = new mongoose.Schema({ // pretty sure this is in bytes fileSize: Number, // TODO: should support highQualityFileSize as well for compressions + videoQualities: [ + { + quality: 'String', + fileSizeInMb: Number, + bitrate: Number, + status: {type: String, enum: ['pending', 'converting', 'complete'], default: 'pending'} + } + ], + bitrateInKbps: Number, dimensions: { height: String, diff --git a/package-lock.json b/package-lock.json index e25d570c..4ca1cac3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "NodeTube", - "version": "1.0.0", + "version": "1.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -117,6 +117,11 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-13.5.2.tgz", "integrity": "sha512-Fr6a47c84PRLfd7M7u3/hEknyUdQrrBA6VoPmkze0tcflhU5UnpWEX2kn12ktA/lb+MNHSqFlSiPHIHsaErTPA==" }, + "@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==" + }, "@types/range-parser": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", @@ -1080,6 +1085,94 @@ "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=" }, + "bull": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/bull/-/bull-3.18.0.tgz", + "integrity": "sha512-nE/BKlg1dnJ/AcOy5D1nzthcmpAKqpUVXzQ43mJfnVC8ZM7mi4ZzP3spN7745UuikzmGGsbTe9px2TbEKhR+DQ==", + "requires": { + "cron-parser": "^2.13.0", + "debuglog": "^1.0.0", + "get-port": "^5.1.1", + "ioredis": "^4.14.1", + "lodash": "^4.17.19", + "p-timeout": "^3.2.0", + "promise.prototype.finally": "^3.1.2", + "semver": "^7.3.2", + "util.promisify": "^1.0.1", + "uuid": "^8.3.0" + }, + "dependencies": { + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==" + } + } + }, + "bull-board": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/bull-board/-/bull-board-0.9.0.tgz", + "integrity": "sha512-Ek6zNREJSPWT+j7GyZRMHDXprrFfeLYzJNV0EIUqhiUkCd8NV3F9qGa/0vThxB0OxcoMp/mDVdhQYz7OTlmrlw==", + "requires": { + "body-parser": "^1.17.2", + "bull": "3.11.0", + "date-fns": "2.4.1", + "ejs": "^2.6.1", + "express": "^4.15.2", + "express-async-router": "^0.1.15", + "pretty-bytes": "^5.1.0", + "ramda": "^0.26.1", + "react": "16.10.2", + "react-dom": "16.10.2", + "react-highlight": "^0.12.0", + "redis-info": "^3.0.8" + }, + "dependencies": { + "bull": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/bull/-/bull-3.11.0.tgz", + "integrity": "sha512-QQOn63RkL6CfnmZcacPVg1EF42SwQcYxNSn9OGlM5S2JW+Gah/dwCcXxZQ3h2nYnhsNfBsherJ7EpLzIsi2kSQ==", + "requires": { + "cron-parser": "^2.13.0", + "debuglog": "^1.0.0", + "get-port": "^5.0.0", + "ioredis": "^4.14.1", + "lodash": "^4.17.15", + "p-timeout": "^3.1.0", + "promise.prototype.finally": "^3.1.1", + "semver": "^6.3.0", + "util.promisify": "^1.0.0", + "uuid": "^3.3.3" + } + }, + "p-timeout": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", + "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "requires": { + "p-finally": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, "busboy": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", @@ -1425,6 +1518,11 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" }, + "cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -1497,7 +1595,7 @@ "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "integrity": "sha1-w9RaizT9cwYxoRCoolIGgrMdWn8=", "requires": { "delayed-stream": "~1.0.0" } @@ -1844,6 +1942,15 @@ "capture-stack-trace": "^1.0.0" } }, + "cron-parser": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/cron-parser/-/cron-parser-2.16.3.tgz", + "integrity": "sha512-XNJBD1QLFeAMUkZtZQuncAAOgJFWNhBdIbwgD22hZxrcWOImBFMKgPC66GzaXpyoJs7UvYLLgPH/8BRk/7gbZg==", + "requires": { + "is-nan": "^1.3.0", + "moment-timezone": "^0.5.31" + } + }, "cross-spawn": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", @@ -1900,6 +2007,11 @@ "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" }, + "date-fns": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.4.1.tgz", + "integrity": "sha512-2RhmH/sjDSCYW2F3ZQxOUx/I7PvzXpi89aQL2d3OAxSTwLx6NilATeUbe0menFE3Lu5lFkOFci36ivimwYHHxw==" + }, "dayjs": { "version": "1.8.19", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.19.tgz", @@ -1918,6 +2030,11 @@ "ms": "2.0.0" } }, + "debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" + }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -2275,6 +2392,11 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" + }, "email-validator": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz", @@ -3051,6 +3173,34 @@ } } }, + "express-async-router": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/express-async-router/-/express-async-router-0.1.15.tgz", + "integrity": "sha512-fV4AwVHOCtYyECvfSqUcWoKC4leRSjkP+OTv8TLNUByZDk40lfE2Ptky77ZVUctTVnel1nwdAaGTrUuzVWz+Fw==", + "requires": { + "@types/express": "^4.16.0", + "@types/node": "^8.10.36", + "express": "^4.16.4" + }, + "dependencies": { + "@types/express": { + "version": "4.17.8", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz", + "integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/node": { + "version": "8.10.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.64.tgz", + "integrity": "sha512-/EwBIb+imu8Qi/A3NF9sJ9iuKo7yV+pryqjmeRqaU0C4wBAOhas5mdvoYeJ5PCKrh6thRSJHdoasFqh3BQGILA==" + } + } + }, "express-flash": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/express-flash/-/express-flash-0.0.2.tgz", @@ -4277,6 +4427,11 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", "integrity": "sha1-+Xj6TJDR3+f/LWvtoqUV5xO9z0o=" }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==" + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -4645,6 +4800,11 @@ "zero-fill": "^2.2.3" } }, + "highlight.js": { + "version": "9.18.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.3.tgz", + "integrity": "sha512-zBZAmhSupHIl5sITeMqIJnYCDfAEc3Gdkqj65wC1lpI468MMQeeQkhcIAvk+RylAkxrCcI9xy9piHiXeQ1BdzQ==" + }, "hosted-git-info": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", @@ -4930,6 +5090,45 @@ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" }, + "ioredis": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.17.3.tgz", + "integrity": "sha512-iRvq4BOYzNFkDnSyhx7cmJNOi1x/HWYe+A4VXHBu4qpwJaGT1Mp+D2bVGJntH9K/Z/GeOM/Nprb8gB3bmitz1Q==", + "requires": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.1.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "redis-commands": "1.5.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.0.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "requires": { + "redis-errors": "^1.0.0" + } + } + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -5128,6 +5327,14 @@ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.1.tgz", "integrity": "sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw==" }, + "is-nan": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.0.tgz", + "integrity": "sha512-z7bbREymOqt2CCaZVly8aC4ML3Xhfi0ekuOnjO2L8vKdl+CttdVoGZQhd4adMFAsxQ5VeRVwORs4tU8RH+HFtQ==", + "requires": { + "define-properties": "^1.1.3" + } + }, "is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", @@ -5305,8 +5512,7 @@ "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", - "dev": true + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, "js-yaml": { "version": "3.13.1", @@ -5725,6 +5931,14 @@ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -6356,6 +6570,14 @@ "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", "integrity": "sha1-DQVdU/UFKqZTyfbraLtdEr9cK1s=" }, + "moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "requires": { + "moment": ">= 2.9.0" + } + }, "mongodb": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.2.tgz", @@ -7136,7 +7358,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz", "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==", - "dev": true, "requires": { "define-properties": "^1.1.3", "es-abstract": "^1.17.0-next.1" @@ -7711,6 +7932,11 @@ "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, + "pretty-bytes": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.4.1.tgz", + "integrity": "sha512-s1Iam6Gwz3JI5Hweaz4GoCD1WUNUIyzePFy5+Js2hjwGVt2Z79wNN+ZKOZ2vB6C+Xs6njyB84Z1IthQg8d9LxA==" + }, "prettyjson": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz", @@ -7751,6 +7977,16 @@ "asap": "~2.0.3" } }, + "promise.prototype.finally": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz", + "integrity": "sha512-A2HuJWl2opDH0EafgdjwEw7HysI8ff/n4lW4QEVBCUXFk9QeGecBWv0Deph0UmLe3tTNYegz8MOjsVuE6SMoJA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.0", + "function-bind": "^1.1.1" + } + }, "promisify-call": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", @@ -7800,6 +8036,16 @@ } } }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, "proxy-addr": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", @@ -8057,6 +8303,11 @@ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", "integrity": "sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=" }, + "ramda": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", + "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==" + }, "random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -8132,6 +8383,40 @@ } } }, + "react": { + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react/-/react-16.10.2.tgz", + "integrity": "sha512-MFVIq0DpIhrHFyqLU0S3+4dIcBhhOvBE8bJ/5kHPVOVaGdo0KuiQzpcjCPsf585WvhypqtrMILyoE2th6dT+Lw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.10.2", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.10.2.tgz", + "integrity": "sha512-kWGDcH3ItJK4+6Pl9DZB16BXYAZyrYQItU4OMy0jAkv5aNqc+mAKb4TpFtAteI6TJZu+9ZlNhaeNQSVQDHJzkw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.16.2" + } + }, + "react-highlight": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.12.0.tgz", + "integrity": "sha512-j04EWbYOFM0PryhF5Vvl0FDa/dD3M6q0Sl+nFN9kTvWQ9hFkfISNNs85+ssL4TSkDM+4pQTpMdxlDRi8yfIxjw==", + "requires": { + "highlight.js": "^9.11.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "read": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", @@ -8253,6 +8538,19 @@ "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz", "integrity": "sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==" }, + "redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=" + }, + "redis-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/redis-info/-/redis-info-3.0.8.tgz", + "integrity": "sha512-L7yPuGzRq+gu+ZYl/aO0TDgc4nNcMpDTaTN4P3bBi8ZENp1fk8gvtZQpidrYL5uAJYMIcMN81fgUz28qUpTeVA==", + "requires": { + "lodash": "^4.17.11" + } + }, "redis-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", @@ -8744,6 +9042,15 @@ "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" }, + "scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-BqYVWqwz6s1wZMhjFvLfVR5WXP7ZY32M/wYPo04CcuPM7XZEbV2TBNW7Z0UkguPTl0dWMA59VbNXxK6q+pHItg==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "scmp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/scmp/-/scmp-2.1.0.tgz", @@ -9413,6 +9720,11 @@ "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, + "standard-as-callback": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", + "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==" + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", @@ -10325,6 +10637,17 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "util.promisify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz", + "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==", + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.2", + "has-symbols": "^1.0.1", + "object.getownpropertydescriptors": "^2.1.0" + } + }, "utile": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/utile/-/utile-0.3.0.tgz", diff --git a/package.json b/package.json index befe6a42..70d30741 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "NodeTube", - "version": "1.0.0", + "version": "1.0.3", "description": "Video, audio and image hosting", "repository": { "type": "git", @@ -32,6 +32,8 @@ "bcrypt-nodejs": "^0.0.3", "bluebird": "^3.5.4", "body-parser": "^1.19.0", + "bull": "^3.18.0", + "bull-board": "^0.9.0", "captchapng": "0.0.1", "chalk": "^1.1.3", "cheerio": "^0.22.0", diff --git a/views/media.pug b/views/media.pug index 85df3f31..38c4721e 100644 --- a/views/media.pug +++ b/views/media.pug @@ -301,6 +301,17 @@ block content h4.fw(style="font-size:22px;margin-top:30px;") If your upload is stuck on processing, let an admin know via the social links at the bottom of the page and we'll take a look. + if upload.status !== 'processing' + + div(style="max-width:443px;margin:0 auto;") + //if(upload.videoQualities.includes({status: 'pending'})) + // h2.fw wtf + each val in upload.videoQualities + if val.status !== 'complete' + h4.fw(style="font-size:22px;margin-top:30px;") Video #{val.quality} convert is #{val.status} + + + br br @@ -311,7 +322,13 @@ block content video#media_player.display-element(playsinline poster=`${uploadServer}/${upload.uploader.channelUrl}/${upload.thumbnails.generated || upload.thumbnails.medium}` controls='', style="max-width:100%;background-color:black;") // to - source.video-source(src=`${serverToUse}/${upload.uploader.channelUrl}/${upload.uniqueTag}.mp4`, type='video/mp4') + + each val in upload.videoQualities + if val.status === 'complete' + source(src=`${serverToUse}/${upload.uploader.channelUrl}/${upload.uniqueTag}-${val.quality}.mp4`, size=`${val.quality}`, type='video/mp4') + //source.video-source(src=`${serverToUse}/${upload.uploader.channelUrl}/${upload.uniqueTag}.mp4`, type='video/mp4') + //source(src=upload.uploadUrl, type='video/mp4') + //source.video-source(src=`${serverToUse}/${upload.uploader.channelUrl}/${upload.uniqueTag}.mp4`, type='video/mp4') // TODO: load captions programatically //track(kind='captions', label='English captions', src='/uploads/anthony/lordoftherings.vtt', srclang='en', default='') @@ -319,6 +336,7 @@ block content //source(src=upload.uploadUrl, type='video/mp4') + // if it's an audio else if upload.fileType === 'audio' div @@ -921,7 +939,7 @@ block extra_footer_js if upload.status == 'processing' include ./mediaPlayerPartials/progressTrackerJs - + // include the stuff of media to calculate converstion percentage script(src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.0/clipboard.min.js") script(src="https://cdnjs.cloudflare.com/ajax/libs/plyr/3.5.10/plyr.min.js") @@ -1199,9 +1217,9 @@ block extra_footer_js include ./mediaPlayerPartials/reportUploadFunctionalityJs - include ./mediaPlayerPartials/changeQualityJs - - include ./mediaPlayerPartials/changeUserDefaultQualityJs + //include ./mediaPlayerPartials/changeQualityJs + // + //include ./mediaPlayerPartials/changeUserDefaultQualityJs include mediaPlayerPartials/creditFunctionalityJs diff --git a/views/mediaPlayerPartials/plyrAndAutoplayFunctionalityJs.pug b/views/mediaPlayerPartials/plyrAndAutoplayFunctionalityJs.pug index 9fba590a..698c1861 100644 --- a/views/mediaPlayerPartials/plyrAndAutoplayFunctionalityJs.pug +++ b/views/mediaPlayerPartials/plyrAndAutoplayFunctionalityJs.pug @@ -69,6 +69,7 @@ script. autoplay, clickToPlay: true, speed: {selected: 1, options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2]}, + quality: { default: 144, options: [1080, 720, 480, 360, 240, 144] }, controls: ['play-large', 'play','progress', 'current-time', 'duration', 'rewind', 'fast-forward', 'mute', 'volume', 'settings', 'fullscreen', 'captions'], settings: ['speed', 'captions', 'quality', 'loop'] };