1
0
Fork 0

Refractoring and add thumbnails support (without tests)

This commit is contained in:
Chocobozzz 2016-05-10 21:19:24 +02:00
parent f1dae01868
commit cbe2f7c348
19 changed files with 312 additions and 162 deletions

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ test6/
public/stylesheets/global.css
public/stylesheets/vendor
uploads
thumbnails

View File

@ -16,6 +16,7 @@ storage:
certs: 'certs/'
uploads: 'uploads/'
logs: 'logs/'
thumbnails: 'thumbnails/'
network:
friends: []

View File

@ -13,6 +13,7 @@ storage:
certs: 'test1/certs/'
uploads: 'test1/uploads/'
logs: 'test1/logs/'
thumbnails: 'test1/thumbnails/'
network:
friends:

View File

@ -13,6 +13,7 @@ storage:
certs: 'test2/certs/'
uploads: 'test2/uploads/'
logs: 'test2/logs/'
thumbnails: 'test2/thumbnails/'
network:
friends:

View File

@ -13,6 +13,7 @@ storage:
certs: 'test3/certs/'
uploads: 'test3/uploads/'
logs: 'test3/logs/'
thumbnails: 'test3/thumbnails/'
network:
friends:

View File

@ -13,6 +13,7 @@ storage:
certs: 'test4/certs/'
uploads: 'test4/uploads/'
logs: 'test4/logs/'
thumbnails: 'test4/thumbnails/'
network:
friends:

View File

@ -13,6 +13,7 @@ storage:
certs: 'test5/certs/'
uploads: 'test5/uploads/'
logs: 'test5/logs/'
thumbnails: 'test5/thumbnails/'
network:
friends:

View File

@ -13,6 +13,7 @@ storage:
certs: 'test6/certs/'
uploads: 'test6/uploads/'
logs: 'test6/logs/'
thumbnails: 'test6/thumbnails/'
network:
friends:

View File

@ -75,6 +75,10 @@ app.use('/app/*', function (req, res, next) {
res.sendStatus(404)
})
// Thumbnails path for express
const thumbnails_physical_path = path.join(__dirname, config.get('storage.thumbnails'))
app.use(constants.THUMBNAILS_STATIC_PATH, express.static(thumbnails_physical_path, { maxAge: 0 }))
// Client application
app.use('/*', function (req, res, next) {
res.sendFile(path.join(__dirname, 'client/index.html'))

View File

@ -1,17 +1,16 @@
'use strict'
const express = require('express')
const fs = require('fs')
const logger = require('../../../helpers/logger')
const friends = require('../../../lib/friends')
const middleware = require('../../../middlewares')
const cacheMiddleware = middleware.cache
const peertubeCrypto = require('../../../helpers/peertubeCrypto')
const Pods = require('../../../models/pods')
const reqValidator = middleware.reqValidators.pods
const secureMiddleware = middleware.secure
const secureRequest = middleware.reqValidators.remote.secureRequest
const videos = require('../../../lib/videos')
const Videos = require('../../../models/videos')
const router = express.Router()
@ -34,9 +33,12 @@ function addPods (req, res, next) {
Pods.add(informations, function (err) {
if (err) return next(err)
Videos.addRemotes(informations.videos)
// Create the remote videos from the new pod
videos.createRemoteVideos(informations.videos, function (err) {
if (err) logger.error('Cannot create remote videos.', { error: err })
})
fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
friends.getMyCertificate(function (err, cert) {
if (err) {
logger.error('Cannot read cert file.')
return next(err)
@ -75,11 +77,20 @@ function removePods (req, res, next) {
Pods.remove(url, function (err) {
if (err) return next(err)
Videos.removeAllRemotesOf(url, function (err) {
if (err) logger.error('Cannot remove all remote videos of %s.', url)
else logger.info('%s pod removed.', url)
Videos.listFromUrl(url, function (err, videos_list) {
if (err) {
logger.error('Cannot list videos from url.', { error: err })
next(err)
}
res.type('json').status(204).end()
videos.removeRemoteVideos(videos_list, function (err) {
if (err) {
logger.error('Cannot remove remote videos.', { error: err })
next(err)
}
res.type('json').status(204).end()
})
})
})
}

View File

@ -7,7 +7,9 @@ const middleware = require('../../../middlewares')
const secureMiddleware = middleware.secure
const cacheMiddleware = middleware.cache
const reqValidator = middleware.reqValidators.remote
const videos = require('../../../models/videos')
const logger = require('../../../helpers/logger')
const Videos = require('../../../models/videos')
const videos = require('../../../lib/videos')
const router = express.Router()
@ -34,20 +36,34 @@ module.exports = router
// ---------------------------------------------------------------------------
function addRemoteVideos (req, res, next) {
videos.addRemotes(req.body.data, function (err, videos) {
if (err) return next(err)
const videos_to_create = req.body.data
videos.createRemoteVideos(videos_to_create, function (err, remote_videos) {
if (err) {
logger.error('Cannot create remote videos.', { error: err })
return next(err)
}
res.json(videos)
res.type('json').status(201).end()
})
}
function removeRemoteVideo (req, res, next) {
const url = req.body.signature.url
const fromUrl = req.body.signature.url
const magnetUris = map(req.body.data, 'magnetUri')
videos.removeRemotesOfByMagnetUris(url, magnetUris, function (err) {
if (err) return next(err)
Videos.listFromUrlAndMagnets(fromUrl, magnetUris, function (err, videos_list) {
if (err) {
logger.error('Cannot list videos from url and magnets.', { error: err })
return next(err)
}
res.type('json').status(204).end()
videos.removeRemoteVideos(videos_list, function (err) {
if (err) {
logger.error('Cannot remove remote videos.', { error: err })
return next(err)
}
res.type('json').status(204).end()
})
})
}

View File

@ -1,16 +1,19 @@
'use strict'
const config = require('config')
const crypto = require('crypto')
const express = require('express')
const fs = require('fs')
const path = require('path')
const multer = require('multer')
const constants = require('../../../initializers/constants')
const logger = require('../../../helpers/logger')
const friends = require('../../../lib/friends')
const middleware = require('../../../middlewares')
const oAuth2 = require('../../../middlewares/oauth2')
const cacheMiddleware = middleware.cache
const reqValidator = middleware.reqValidators.videos
const utils = require('../../../helpers/utils')
const Videos = require('../../../models/videos') // model
const videos = require('../../../lib/videos')
const webtorrent = require('../../../lib/webtorrent')
@ -29,14 +32,15 @@ const storage = multer.diskStorage({
if (file.mimetype === 'video/webm') extension = 'webm'
else if (file.mimetype === 'video/mp4') extension = 'mp4'
else if (file.mimetype === 'video/ogg') extension = 'ogv'
crypto.pseudoRandomBytes(16, function (err, raw) {
const fieldname = err ? undefined : raw.toString('hex')
utils.generateRandomString(16, function (err, random_string) {
const fieldname = err ? undefined : random_string
cb(null, fieldname + '.' + extension)
})
}
})
const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
const thumbnailsDir = path.join(__dirname, '..', '..', '..', '..', config.get('storage.thumbnails'))
router.get('/', cacheMiddleware.cache(false), listVideos)
router.post('/', oAuth2.authenticate, reqFiles, reqValidator.videosAdd, cacheMiddleware.cache(false), addVideo)
@ -63,31 +67,50 @@ function addVideo (req, res, next) {
videos.getVideoDuration(video_file.path, function (err, duration) {
if (err) {
// TODO: unseed the video
logger.error('Cannot retrieve metadata of the file')
logger.error('Cannot retrieve metadata of the file.')
return next(err)
}
const video_data = {
name: video_infos.name,
namePath: video_file.filename,
description: video_infos.description,
magnetUri: torrent.magnetURI,
author: res.locals.oauth.token.user.username,
duration: duration
}
Videos.add(video_data, function (err) {
videos.getVideoThumbnail(video_file.path, function (err, thumbnail_name) {
if (err) {
// TODO unseed the video
logger.error('Cannot insert this video in the database.')
// TODO: unseed the video
logger.error('Cannot make a thumbnail of the video file.')
return next(err)
}
// Now we'll add the video's meta data to our friends
friends.addVideoToFriends(video_data)
const video_data = {
name: video_infos.name,
namePath: video_file.filename,
description: video_infos.description,
magnetUri: torrent.magnetURI,
author: res.locals.oauth.token.user.username,
duration: duration,
thumbnail: thumbnail_name
}
// TODO : include Location of the new video -> 201
res.type('json').status(204).end()
Videos.add(video_data, function (err) {
if (err) {
// TODO unseed the video
logger.error('Cannot insert this video in the database.')
return next(err)
}
fs.readFile(thumbnailsDir + thumbnail_name, function (err, data) {
if (err) {
// TODO: remove video?
logger.error('Cannot read the thumbnail of the video')
return next(err)
}
// Set the image in base64
video_data.thumbnail_base64 = new Buffer(data).toString('base64')
// Now we'll add the video's meta data to our friends
friends.addVideoToFriends(video_data)
// TODO : include Location of the new video -> 201
res.type('json').status(204).end()
})
})
})
})
})
@ -123,13 +146,17 @@ function removeVideo (req, res, next) {
Videos.removeOwned(req.params.id, function (err) {
if (err) return next(err)
const params = {
name: video.name,
magnetUri: video.magnetUri
}
videos.removeVideosDataFromDisk([ video ], function (err) {
if (err) logger.error('Cannot remove video data from disk.', { video: video })
friends.removeVideoToFriends(params)
res.type('json').status(204).end()
const params = {
name: video.name,
magnetUri: video.magnetUri
}
friends.removeVideoToFriends(params)
res.type('json').status(204).end()
})
})
})
})
@ -154,7 +181,8 @@ function getFormatedVideo (video_obj) {
isLocal: videos.getVideoState(video_obj).owned,
magnetUri: video_obj.magnetUri,
author: video_obj.author,
duration: video_obj.duration
duration: video_obj.duration,
thumbnail_path: constants.THUMBNAILS_STATIC_PATH + '/' + video_obj.thumbnail
}
return formated_video

View File

@ -1,9 +1,20 @@
'use strict'
const crypto = require('crypto')
const logger = require('./logger')
const utils = {
cleanForExit: cleanForExit
cleanForExit: cleanForExit,
generateRandomString: generateRandomString
}
function generateRandomString (size, callback) {
crypto.pseudoRandomBytes(size, function (err, raw) {
if (err) return callback(err)
callback(null, raw.toString('hex'))
})
}
function cleanForExit (webtorrent_process) {

View File

@ -18,6 +18,12 @@ const PODS_SCORE = {
// Number of retries we make for the make retry requests (to friends...)
let REQUEST_RETRIES = 10
// Videos thumbnail size
const THUMBNAILS_SIZE = '200x110'
// Path for access to thumbnails with express router
const THUMBNAILS_STATIC_PATH = '/static/thumbnails'
// Special constants for a test instance
if (isTestInstance() === true) {
FRIEND_BASE_SCORE = 20
@ -32,7 +38,9 @@ module.exports = {
FRIEND_BASE_SCORE: FRIEND_BASE_SCORE,
INTERVAL: INTERVAL,
PODS_SCORE: PODS_SCORE,
REQUEST_RETRIES: REQUEST_RETRIES
REQUEST_RETRIES: REQUEST_RETRIES,
THUMBNAILS_SIZE: THUMBNAILS_SIZE,
THUMBNAILS_STATIC_PATH: THUMBNAILS_STATIC_PATH
}
// ---------------------------------------------------------------------------

View File

@ -11,6 +11,7 @@ const peertubeCrypto = require('../helpers/peertubeCrypto')
const Pods = require('../models/pods')
const requestsScheduler = require('../lib/requestsScheduler')
const requests = require('../helpers/requests')
const videos = require('../lib/videos')
const Videos = require('../models/videos')
const http = config.get('webserver.https') ? 'https' : 'http'
@ -20,6 +21,7 @@ const port = config.get('webserver.port')
const pods = {
addVideoToFriends: addVideoToFriends,
hasFriends: hasFriends,
getMyCertificate: getMyCertificate,
makeFriends: makeFriends,
quitFriends: quitFriends,
removeVideoToFriends: removeVideoToFriends
@ -42,11 +44,15 @@ function hasFriends (callback) {
})
}
function getMyCertificate (callback) {
fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', callback)
}
function makeFriends (callback) {
const pods_score = {}
logger.info('Make friends!')
fs.readFile(peertubeCrypto.getCertDir() + 'peertube.pub', 'utf8', function (err, cert) {
getMyCertificate(function (err, cert) {
if (err) {
logger.error('Cannot read public cert.')
return callback(err)
@ -54,8 +60,8 @@ function makeFriends (callback) {
const urls = config.get('network.friends')
async.each(urls, function (url, callback) {
computeForeignPodsList(url, pods_score, callback)
async.each(urls, function (url, callback_each) {
computeForeignPodsList(url, pods_score, callback_each)
}, function (err) {
if (err) return callback(err)
@ -96,11 +102,18 @@ function quitFriends (callback) {
logger.info('Broke friends, so sad :(')
Videos.removeAllRemotes(function (err) {
Videos.listFromRemotes(function (err, videos_list) {
if (err) return callback(err)
logger.info('Removed all remote videos.')
callback(null)
videos.removeRemoteVideos(videos_list, function (err) {
if (err) {
logger.error('Cannot remove remote videos.', { error: err })
return callback(err)
}
logger.info('Removed all remote videos.')
callback(null)
})
})
})
})
@ -127,16 +140,14 @@ function computeForeignPodsList (url, pods_score, callback) {
if (err) return callback(err)
if (foreign_pods_list.length === 0) return callback()
async.each(foreign_pods_list, function (foreign_pod, callback_each) {
foreign_pods_list.forEach(function (foreign_pod) {
const foreign_url = foreign_pod.url
if (pods_score[foreign_url]) pods_score[foreign_url]++
else pods_score[foreign_url] = 1
callback_each()
}, function () {
callback()
})
callback()
})
}
@ -194,13 +205,15 @@ function makeRequestsToWinningPods (cert, pods_list, callback) {
logger.error('Error with adding %s pod.', pod.url, { error: err })
return callback_each_request()
}
Videos.addRemotes(body.videos, function (err) {
console.log('hihi')
videos.createRemoteVideos(body.videos, function (err) {
if (err) {
logger.error('Error with adding videos of pod.', pod.url, { error: err })
return callback_each_request()
}
console.log('kik')
logger.debug('Adding remote videos from %s.', pod.url, { videos: body.videos })
return callback_each_request()
})

View File

@ -8,6 +8,7 @@ const logger = require('../helpers/logger')
const Pods = require('../models/pods')
const Requests = require('../models/requests')
const requests = require('../helpers/requests')
const videos = require('../lib/videos')
const Videos = require('../models/videos')
let timer = null
@ -99,7 +100,7 @@ function makeRequest (type, requests_to_make, callback) {
requests.makeMultipleRetryRequest(params, pods, callbackEachPodFinished, callbackAllPodsFinished)
function callbackEachPodFinished (err, response, body, url, pod, callback_each_pod_finished) {
if (err || (response.statusCode !== 200 && response.statusCode !== 204)) {
if (err || (response.statusCode !== 200 && response.statusCode !== 201 && response.statusCode !== 204)) {
bad_pods.push(pod._id)
logger.error('Error sending secure request to %s pod.', url, { error: err || new Error('Status code not 20x') })
} else {
@ -187,12 +188,13 @@ function removeBadPods () {
const urls = map(pods, 'url')
const ids = map(pods, '_id')
Videos.removeAllRemotesOf(urls, function (err, r) {
Videos.listFromUrls(urls, function (err, videos_list) {
if (err) {
logger.error('Cannot remove videos from a pod that we removing.', { error: err })
logger.error('Cannot list videos urls.', { error: err, urls: urls })
} else {
const videos_removed = r.result.n
logger.info('Removed %d videos.', videos_removed)
videos.removeRemoteVideos(videos_list, function (err) {
if (err) logger.error('Cannot remove remote videos.', { error: err })
})
}
Pods.removeAllByIds(ids, function (err, r) {

View File

@ -3,21 +3,39 @@
const async = require('async')
const config = require('config')
const ffmpeg = require('fluent-ffmpeg')
const fs = require('fs')
const map = require('lodash/map')
const pathUtils = require('path')
const constants = require('../initializers/constants')
const logger = require('../helpers/logger')
const utils = require('../helpers/utils')
const Videos = require('../models/videos')
const webtorrent = require('../lib/webtorrent')
const logger = require('../helpers/logger')
const Videos = require('../models/videos')
const uploadDir = pathUtils.join(__dirname, '..', '..', config.get('storage.uploads'))
const thumbnailsDir = pathUtils.join(__dirname, '..', '..', config.get('storage.thumbnails'))
const videos = {
createRemoteVideos: createRemoteVideos,
getVideoDuration: getVideoDuration,
getVideoState: getVideoState,
getVideoThumbnail: getVideoThumbnail,
removeVideosDataFromDisk: removeVideosDataFromDisk,
removeRemoteVideos: removeRemoteVideos,
seed: seed,
seedAllExisting: seedAllExisting
}
function createRemoteVideos (videos, callback) {
// Create the remote videos from the new pod
createRemoteVideoObjects(videos, function (err, remote_videos) {
if (err) return callback(err)
Videos.addRemotes(remote_videos, callback)
})
}
function getVideoDuration (video_path, callback) {
ffmpeg.ffprobe(video_path, function (err, metadata) {
if (err) return callback(err)
@ -36,6 +54,51 @@ function getVideoState (video) {
return { exist: exist, owned: owned }
}
function getVideoThumbnail (video_path, callback) {
const filename = pathUtils.basename(video_path) + '.jpg'
ffmpeg(video_path)
.on('error', callback)
.on('end', function () {
callback(null, filename)
})
.thumbnail({
count: 1,
folder: thumbnailsDir,
size: constants.THUMBNAILS_SIZE,
filename: filename
})
}
// Remove video datas from disk (video file, thumbnail...)
function removeVideosDataFromDisk (videos, callback) {
async.each(videos, function (video, callback_each) {
fs.unlink(thumbnailsDir + video.thumbnail, function (err) {
if (err) logger.error('Cannot remove the video thumbnail')
if (getVideoState(video).owned === true) {
fs.unlink(uploadDir + video.namePath, function (err) {
if (err) {
logger.error('Cannot remove this video file.')
return callback_each(err)
}
callback_each(null)
})
} else {
callback_each(null)
}
})
}, callback)
}
function removeRemoteVideos (videos, callback) {
Videos.removeByIds(map(videos, '_id'), function (err) {
if (err) return callback(err)
removeVideosDataFromDisk(videos, callback)
})
}
function seed (path, callback) {
logger.info('Seeding %s...', path)
@ -69,3 +132,42 @@ function seedAllExisting (callback) {
// ---------------------------------------------------------------------------
module.exports = videos
// ---------------------------------------------------------------------------
function createRemoteVideoObjects (videos, callback) {
const remote_videos = []
async.each(videos, function (video, callback_each) {
// Creating the thumbnail for this remote video
utils.generateRandomString(16, function (err, random_string) {
if (err) return callback_each(err)
const thumbnail_name = random_string + '.jpg'
createThumbnailFromBase64(thumbnail_name, video.thumbnail_base64, function (err) {
if (err) return callback_each(err)
const params = {
name: video.name,
description: video.description,
magnetUri: video.magnetUri,
podUrl: video.podUrl,
duration: video.duration,
thumbnail: thumbnail_name
}
remote_videos.push(params)
callback_each(null)
})
})
},
function (err) {
if (err) return callback(err)
callback(null, remote_videos)
})
}
function createThumbnailFromBase64 (thumbnail_name, data, callback) {
fs.writeFile(thumbnailsDir + thumbnail_name, data, { encoding: 'base64' }, callback)
}

View File

@ -1,18 +1,13 @@
'use strict'
const async = require('async')
const config = require('config')
const dz = require('dezalgo')
const fs = require('fs')
const mongoose = require('mongoose')
const path = require('path')
const logger = require('../helpers/logger')
const http = config.get('webserver.https') === true ? 'https' : 'http'
const host = config.get('webserver.host')
const port = config.get('webserver.port')
const uploadDir = path.join(__dirname, '..', '..', config.get('storage.uploads'))
// ---------------------------------------------------------------------------
@ -23,7 +18,8 @@ const videosSchema = mongoose.Schema({
magnetUri: String,
podUrl: String,
author: String,
duration: Number
duration: Number,
thumbnail: String
})
const VideosDB = mongoose.model('videos', videosSchema)
@ -34,11 +30,13 @@ const Videos = {
addRemotes: addRemotes,
get: get,
list: list,
listFromUrl: listFromUrl,
listFromUrls: listFromUrls,
listFromUrlAndMagnets: listFromUrlAndMagnets,
listFromRemotes: listFromRemotes,
listOwned: listOwned,
removeOwned: removeOwned,
removeAllRemotes: removeAllRemotes,
removeAllRemotesOf: removeAllRemotesOf,
removeRemotesOfByMagnetUris: removeRemotesOfByMagnetUris,
removeByIds: removeByIds,
search: search
}
@ -58,38 +56,13 @@ function add (video, callback) {
})
}
// TODO: avoid doublons
function addRemotes (videos, callback) {
if (!callback) callback = function () {}
const to_add = []
async.each(videos, function (video, callback_each) {
callback_each = dz(callback_each)
logger.debug('Add remote video from pod: %s', video.podUrl)
const params = {
name: video.name,
namePath: null,
description: video.description,
magnetUri: video.magnetUri,
podUrl: video.podUrl,
duration: video.duration
}
to_add.push(params)
callback_each()
}, function () {
VideosDB.create(to_add, function (err, videos) {
if (err) {
logger.error('Cannot insert this remote video.')
return callback(err)
}
return callback(null, videos)
})
videos.forEach(function (video) {
// Ensure they are remote videos
video.namePath = null
})
VideosDB.create(videos, callback)
}
function get (id, callback) {
@ -114,6 +87,22 @@ function list (callback) {
})
}
function listFromUrl (fromUrl, callback) {
VideosDB.find({ podUrl: fromUrl }, callback)
}
function listFromUrls (fromUrls, callback) {
VideosDB.find({ podUrl: { $in: fromUrls } }, callback)
}
function listFromUrlAndMagnets (fromUrl, magnets, callback) {
VideosDB.find({ podUrl: fromUrl, magnetUri: { $in: magnets } }, callback)
}
function listFromRemotes (callback) {
VideosDB.find({ namePath: null }, callback)
}
function listOwned (callback) {
// If namePath is not null this is *our* video
VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) {
@ -126,65 +115,14 @@ function listOwned (callback) {
})
}
// Return the video in the callback
function removeOwned (id, callback) {
VideosDB.findByIdAndRemove(id, function (err, video) {
if (err) {
logger.error('Cannot remove the torrent.')
return callback(err)
}
fs.unlink(uploadDir + video.namePath, function (err) {
if (err) {
logger.error('Cannot remove this video file.')
return callback(err)
}
callback(null)
})
})
}
function removeAllRemotes (callback) {
VideosDB.remove({ namePath: null }, callback)
}
function removeAllRemotesOf (fromUrl, callback) {
VideosDB.remove({ podUrl: fromUrl }, callback)
VideosDB.findByIdAndRemove(id, callback)
}
// Use the magnet Uri because the _id field is not the same on different servers
function removeRemotesOfByMagnetUris (fromUrl, magnetUris, callback) {
if (callback === undefined) callback = function () {}
VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) {
if (err || !videos) {
logger.error('Cannot find the torrent URI of these remote videos.')
return callback(err)
}
const to_remove = []
async.each(videos, function (video, callback_async) {
callback_async = dz(callback_async)
if (video.podUrl !== fromUrl) {
logger.error('The pod %s has not the rights on the video of %s.', fromUrl, video.podUrl)
} else {
to_remove.push(video._id)
}
callback_async()
}, function () {
VideosDB.remove({ _id: { $in: to_remove } }, function (err) {
if (err) {
logger.error('Cannot remove the remote videos.')
return callback(err)
}
logger.info('Removed remote videos from %s.', fromUrl)
callback(null)
})
})
})
function removeByIds (ids, callback) {
VideosDB.remove({ _id: { $in: ids } }, callback)
}
function search (name, callback) {

View File

@ -193,14 +193,23 @@ describe('Test multiple pods', function () {
expect(videos).to.be.an('array')
expect(videos.length).to.equal(4)
const video1 = videos[2]
// We not sure about the order of the two last uploads
let video1 = null
let video2 = null
if (videos[2].name === 'my super name for pod 3') {
video1 = videos[2]
video2 = videos[3]
} else {
video1 = videos[3]
video2 = videos[2]
}
expect(video1.name).to.equal('my super name for pod 3')
expect(video1.description).to.equal('my super description for pod 3')
expect(video1.podUrl).to.equal('http://localhost:9003')
expect(video1.magnetUri).to.exist
expect(video1.duration).to.equal(5)
const video2 = videos[3]
expect(video2.name).to.equal('my super name for pod 3-2')
expect(video2.description).to.equal('my super description for pod 3-2')
expect(video2.podUrl).to.equal('http://localhost:9003')