--- /dev/null
+{
+ "extends": "standard-with-typescript",
+ "rules": {
+ "eol-last": [
+ "error",
+ "always"
+ ],
+ "indent": "off",
+ "no-lone-blocks": "off",
+ "no-mixed-operators": "off",
+ "max-len": [
+ "error",
+ {
+ "code": 140
+ }
+ ],
+ "array-bracket-spacing": [
+ "error",
+ "always"
+ ],
+ "quote-props": [
+ "error",
+ "consistent-as-needed"
+ ],
+ "padded-blocks": "off",
+ "no-async-promise-executor": "off",
+ "dot-notation": "off",
+ "promise/param-names": "off",
+ "import/first": "off",
+ "operator-linebreak": [
+ "error",
+ "after",
+ {
+ "overrides": {
+ "?": "before",
+ ":": "before"
+ }
+ }
+ ],
+ "@typescript-eslint/indent": [
+ "error",
+ 2,
+ {
+ "SwitchCase": 1,
+ "MemberExpression": "off"
+ }
+ ],
+ "@typescript-eslint/consistent-type-assertions": [
+ "error",
+ {
+ "assertionStyle": "as"
+ }
+ ],
+ "@typescript-eslint/array-type": [
+ "error",
+ {
+ "default": "array"
+ }
+ ],
+ "@typescript-eslint/restrict-template-expressions": [
+ "off",
+ {
+ "allowNumber": "true"
+ }
+ ],
+ "@typescript-eslint/quotes": "off",
+ "@typescript-eslint/no-var-requires": "off",
+ "@typescript-eslint/explicit-function-return-type": "off",
+ "@typescript-eslint/promise-function-async": "off",
+ "@typescript-eslint/no-dynamic-delete": "off",
+ "@typescript-eslint/strict-boolean-expressions": "off",
+ "@typescript-eslint/consistent-type-definitions": "off",
+ "@typescript-eslint/no-misused-promises": "off",
+ "@typescript-eslint/no-namespace": "off",
+ "@typescript-eslint/no-extraneous-class": "off",
+ // bugged but useful
+ "@typescript-eslint/restrict-plus-operands": "off"
+ },
+ "ignorePatterns": [
+ "node_modules/"
+ ],
+ "parserOptions": {
+ "project": [
+ "./tsconfig.json",
+ "./server/tools/tsconfig.json"
+ ]
+ }
+}
"ng": "ng",
"nodemon": "nodemon",
"ts-node": "ts-node",
- "tslint": "tslint",
+ "eslint": "eslint",
"concurrently": "concurrently",
"mocha-parallel-tests": "mocha-parallel-tests",
"sasslint": "sass-lint --verbose --no-exit",
"express": "^4.12.4",
"express-oauth-server": "^2.0.0",
"express-rate-limit": "^4.0.4",
- "express-validator": "^6.1.1",
+ "express-validator": "^6.4.0",
"flat": "^5.0.0",
"fluent-ffmpeg": "^2.1.0",
"fs-extra": "^8.0.1",
"webtorrent": "^0.107.16",
"winston": "3.2.1",
"ws": "^7.0.0",
- "youtube-dl": "^3.0.1"
+ "youtube-dl": "^3.0.2"
},
"devDependencies": {
"@types/apicache": "^1.2.0",
"@types/validator": "^12.0.1",
"@types/webtorrent": "^0.107.0",
"@types/ws": "^7.2.1",
+ "@typescript-eslint/eslint-plugin": "^2.18.0",
"chai": "^4.1.1",
"chai-json-schema": "^1.5.0",
"chai-xml": "^0.3.2",
"concurrently": "^5.0.0",
+ "eslint": "^6.8.0",
+ "eslint-config-standard-with-typescript": "^12.0.1",
+ "eslint-plugin-import": "^2.20.1",
+ "eslint-plugin-node": "^11.0.0",
+ "eslint-plugin-promise": "^4.2.1",
+ "eslint-plugin-standard": "^4.0.1",
"libxmljs": "0.19.7",
"maildev": "^1.0.0-rc3",
"marked": "^0.8.0",
"supertest": "^4.0.2",
"swagger-cli": "^3.0.1",
"ts-node": "8.6.2",
- "tslint": "^6.0.0",
- "tslint-config-standard": "^9.0.0",
"typescript": "^3.7.2"
},
"scripty": {
npm run build:server
sh ./server/tests/api/ci-4.sh 2
elif [ "$1" = "lint" ]; then
- npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts"
+ npm run eslint -- --ext .ts "server/**/*.ts" "shared/**/*.ts"
npm run swagger-cli -- validate support/doc/api/openapi.yaml
( cd client
}
await JobQueue.Instance.init()
- await JobQueue.Instance.createJob({ type: 'video-file-import', payload: dataInput })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-file-import', payload: dataInput })
console.log('Import job for video %s created.', video.uuid)
}
await JobQueue.Instance.init()
for (const d of dataInput) {
- await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: d })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: d })
console.log('Transcoding job for video %s created.', video.uuid)
}
}
activityPubClientRouter.get('/video-channels/:name',
executeIfActivityPub,
asyncMiddleware(localVideoChannelValidator),
- asyncMiddleware(videoChannelController)
+ videoChannelController
)
activityPubClientRouter.get('/video-channels/:name/followers',
executeIfActivityPub,
activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
executeIfActivityPub,
asyncMiddleware(videoPlaylistElementAPGetValidator),
- asyncMiddleware(videoPlaylistElementController)
+ videoPlaylistElementController
)
// ---------------------------------------------------------------------------
return activityPubResponse(activityPubContextify(json), res)
}
-async function videoChannelController (req: express.Request, res: express.Response) {
+function videoChannelController (req: express.Request, res: express.Response) {
const videoChannel = res.locals.videoChannel
return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
return activityPubResponse(activityPubContextify(object), res)
}
-async function videoPlaylistElementController (req: express.Request, res: express.Response) {
+function videoPlaylistElementController (req: express.Request, res: express.Response) {
const videoPlaylistElement = res.locals.videoPlaylistElementAP
const json = videoPlaylistElement.toActivityPubObject()
processActivities(task.activities, options)
.then(() => cb())
+ .catch(err => {
+ logger.error('Error in process activities.', { err })
+ cb()
+ })
})
function inboxController (req: express.Request, res: express.Response) {
accountNameWithHostGetValidator,
accountsSortValidator,
ensureAuthUserOwnsAccountValidator,
- videosSortValidator,
- videoChannelsSortValidator
+ videoChannelsSortValidator,
+ videosSortValidator
} from '../../middlewares/validators'
import { AccountModel } from '../../models/account/account'
import { AccountVideoRateModel } from '../../models/account/account-video-rate'
import { VideoModel } from '../../models/video/video'
-import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils'
+import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
import { VideoChannelModel } from '../../models/video/video-channel'
import { JobQueue } from '../../lib/job-queue'
-import { logger } from '../../helpers/logger'
import { VideoPlaylistModel } from '../../models/video/video-playlist'
-import {
- commonVideoPlaylistFiltersValidator,
- videoPlaylistsSearchValidator
-} from '../../middlewares/validators/videos/video-playlists'
+import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists'
const accountsRouter = express.Router()
if (account.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } })
- .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err }))
}
return res.json(account.toFormattedJSON())
configRouter.get('/custom',
authenticate,
ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
- asyncMiddleware(getCustomConfig)
+ getCustomConfig
)
configRouter.put('/custom',
authenticate,
ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
- asyncMiddleware(customConfigUpdateValidator),
+ customConfigUpdateValidator,
asyncMiddleware(updateCustomConfig)
)
configRouter.delete('/custom',
return res.json(about).end()
}
-async function getCustomConfig (req: express.Request, res: express.Response) {
+function getCustomConfig (req: express.Request, res: express.Response) {
const data = customConfig()
return res.json(data).end()
function getEnabledResolutions () {
return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
- .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true)
+ .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
.map(r => parseInt(r, 10))
}
allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
threads: CONFIG.TRANSCODING.THREADS,
resolutions: {
- '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ],
- '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ],
- '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ],
- '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ],
- '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ],
- '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ],
- '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ]
+ '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'],
+ '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'],
+ '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'],
+ '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'],
+ '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'],
+ '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'],
+ '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p']
},
webtorrent: {
enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
})
const total = await JobQueue.Instance.count(state)
- const result: ResultList<any> = {
+ const result: ResultList<Job> = {
total,
data: jobs.map(j => formatJob(j, state))
}
const buildSamples = memoizee(async function () {
const [ categories, channels, tags ] = await Promise.all([
VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
- VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT),
+ VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
])
import * as express from 'express'
import { UserRight } from '../../../../shared/models/users'
-import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares'
+import { authenticate, ensureUserHasRight } from '../../../middlewares'
const debugRouter = express.Router()
debugRouter.get('/debug',
authenticate,
ensureUserHasRight(UserRight.MANAGE_DEBUG),
- asyncMiddleware(getDebug)
+ getDebug
)
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
-async function getDebug (req: express.Request, res: express.Response) {
+function getDebug (req: express.Request, res: express.Response) {
return res.json({
ip: req.ip
}).end()
}
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
- .catch(err => logger.error('Cannot create follow job for %s.', host, err))
}
return res.status(204).end()
}
async function generateOutput (options: {
- startDateQuery: string,
- endDateQuery?: string,
- level: LogLevel,
+ startDateQuery: string
+ endDateQuery?: string
+ level: LogLevel
nameFilter: RegExp
}) {
const { startDateQuery, level, nameFilter } = options
const output: any[] = []
for (let i = lines.length - 1; i >= 0; i--) {
- const line = lines[ i ]
+ const line = lines[i]
let log: any
try {
}
logTime = new Date(log.timestamp).getTime()
- if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) {
+ if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) {
output.push(log)
currentSize += line.length
videoId: res.locals.onlyVideo.id
}
- await JobQueue.Instance.createJob({
+ await JobQueue.Instance.createJobWithPromise({
type: 'video-redundancy',
payload
})
)
meRouter.delete('/me',
authenticate,
- asyncMiddleware(deleteMeValidator),
+ deleteMeValidator,
asyncMiddleware(deleteMe)
)
}
async function updateMyAvatar (req: express.Request, res: express.Response) {
- const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
+ const avatarPhysicalFile = req.files['avatarfile'][0]
const user = res.locals.oauth.token.user
const userAccount = await AccountModel.load(user.Account.id)
import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
import { JobQueue } from '../../../lib/job-queue'
-import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers/database'
const mySubscriptionsRouter = express.Router()
mySubscriptionsRouter.post('/me/subscriptions',
authenticate,
userSubscriptionAddValidator,
- asyncMiddleware(addUserSubscription)
+ addUserSubscription
)
mySubscriptionsRouter.get('/me/subscriptions/:uri',
return res.json(existObject)
}
-async function addUserSubscription (req: express.Request, res: express.Response) {
+function addUserSubscription (req: express.Request, res: express.Response) {
const user = res.locals.oauth.token.User
const [ name, host ] = req.body.uri.split('@')
}
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
- .catch(err => logger.error('Cannot create follow job for subscription %s.', req.body.uri, err))
return res.status(204).end()
}
}
async function updateVideoChannelAvatar (req: express.Request, res: express.Response) {
- const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
+ const avatarPhysicalFile = req.files['avatarfile'][0]
const videoChannel = res.locals.videoChannel
const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
if (videoChannelWithVideos.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } })
- .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err }))
}
return res.json(videoChannelWithVideos.toFormattedJSON())
if (videoPlaylist.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } })
- .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err }))
}
return res.json(videoPlaylist.toFormattedJSON())
const buf = await readFile(torrentfile.path)
const parsedTorrent = parseTorrent(buf)
- videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string
+ videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string
} else {
magnetUri = body.magnetUri
const parsed = magnetUtil.decode(magnetUri)
- videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string
+ videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string
}
const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName })
videoImportId: videoImport.id,
magnetUri
}
- await JobQueue.Instance.createJob({ type: 'video-import', payload })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
downloadThumbnail: !thumbnailModel,
downloadPreview: !previewModel
}
- await JobQueue.Instance.createJob({ type: 'video-import', payload })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
async function processThumbnail (req: express.Request, video: VideoModel) {
const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
if (thumbnailField) {
- const thumbnailPhysicalFile = thumbnailField[ 0 ]
+ const thumbnailPhysicalFile = thumbnailField[0]
return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false)
}
}
function insertIntoDB (parameters: {
- video: MVideoThumbnailAccountDefault,
- thumbnailModel: MThumbnail,
- previewModel: MThumbnail,
- videoChannel: MChannelAccountDefault,
- tags: string[],
- videoImportAttributes: Partial<MVideoImport>,
+ video: MVideoThumbnailAccountDefault
+ thumbnailModel: MThumbnail
+ previewModel: MThumbnail
+ videoChannel: MChannelAccountDefault
+ tags: string[]
+ videoImportAttributes: Partial<MVideoImport>
user: MUser
}): Bluebird<MVideoImportFormattable> {
const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters
VIDEO_CATEGORIES,
VIDEO_LANGUAGES,
VIDEO_LICENCES,
- VIDEO_PRIVACIES,
- VIDEO_TRANSCODING_FPS
+ VIDEO_PRIVACIES
} from '../../../initializers/constants'
import {
changeVideoChannelShare,
}
}
- await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput })
}
Hooks.runAction('action:api.video.uploaded', { video: videoCreated })
if (video.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
- .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
}
return res.json(video.toFormattedDetailsJSON())
// ---------------------------------------------------------------------------
-async function serveServerTranslations (req: express.Request, res: express.Response) {
+function serveServerTranslations (req: express.Request, res: express.Response) {
const locale = req.params.locale
const file = req.params.file
staticRouter.use(
STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent',
asyncMiddleware(videosDownloadValidator),
- asyncMiddleware(downloadTorrent)
+ downloadTorrent
)
staticRouter.use(
STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent',
asyncMiddleware(videosDownloadValidator),
- asyncMiddleware(downloadHLSVideoFileTorrent)
+ downloadHLSVideoFileTorrent
)
// Videos path for webseeding
staticRouter.use(
STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
asyncMiddleware(videosDownloadValidator),
- asyncMiddleware(downloadVideoFile)
+ downloadVideoFile
)
staticRouter.use(
STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
asyncMiddleware(videosDownloadValidator),
- asyncMiddleware(downloadHLSVideoFile)
+ downloadHLSVideoFile
)
// HLS
return res.send(json).end()
}
-async function downloadTorrent (req: express.Request, res: express.Response) {
+function downloadTorrent (req: express.Request, res: express.Response) {
const video = res.locals.videoAll
const videoFile = getVideoFile(req, video.VideoFiles)
return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`)
}
-async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
+function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
const video = res.locals.videoAll
const playlist = getHLSPlaylist(video)
return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`)
}
-async function downloadVideoFile (req: express.Request, res: express.Response) {
+function downloadVideoFile (req: express.Request, res: express.Response) {
const video = res.locals.videoAll
const videoFile = getVideoFile(req, video.VideoFiles)
return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`)
}
-async function downloadHLSVideoFile (req: express.Request, res: express.Response) {
+function downloadHLSVideoFile (req: express.Request, res: express.Response) {
const video = res.locals.videoAll
const playlist = getHLSPlaylist(video)
if (!playlist) return res.status(404).end
import { Server as WebSocketServer } from 'ws'
import { TRACKER_RATE_LIMITS } from '../initializers/constants'
import { VideoFileModel } from '../models/video/video-file'
-import { parse } from 'url'
import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
import { CONFIG } from '../initializers/config'
const key = ip + '-' + infoHash
- peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1
- peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1
+ peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1
+ peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1
- if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
- return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`))
+ if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
+ return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`))
}
try {
trackerServer.onWebSocketConnection(ws)
})
- server.on('upgrade', (request, socket, head) => {
- const pathname = parse(request.url).pathname
-
- if (pathname === '/tracker/socket') {
+ server.on('upgrade', (request: express.Request, socket, head) => {
+ if (request.path === '/tracker/socket') {
wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request))
}
import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants'
import { signJsonLDObject } from './peertube-crypto'
import { pageToStartAndCount } from './core-utils'
-import { parse } from 'url'
+import { URL } from 'url'
import { MActor, MVideoAccountLight } from '../typings/models'
function activityPubContextify <T> (data: T) {
}
function checkUrlsSameHost (url1: string, url2: string) {
- const idHost = parse(url1).host
- const actorHost = parse(url2).host
+ const idHost = new URL(url1).host
+ const actorHost = new URL(url2).host
return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
}
}
abstract class EntityAuditView {
- constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { }
+ constructor (private readonly keysToKeep: string[], private readonly prefix: string, private readonly entityInfos: object) { }
+
toLogKeys (): object {
return chain(flatten(this.entityInfos, { delimiter: '-', safe: true }))
.pick(this.keysToKeep)
'downloadEnabled'
]
class VideoAuditView extends EntityAuditView {
- constructor (private video: VideoDetails) {
+ constructor (private readonly video: VideoDetails) {
super(videoKeysToKeep, 'video', video)
}
}
'video-name'
]
class VideoImportAuditView extends EntityAuditView {
- constructor (private videoImport: VideoImport) {
+ constructor (private readonly videoImport: VideoImport) {
super(videoImportKeysToKeep, 'video-import', videoImport)
}
}
'account-name'
]
class CommentAuditView extends EntityAuditView {
- constructor (private comment: VideoComment) {
+ constructor (private readonly comment: VideoComment) {
super(commentKeysToKeep, 'comment', comment)
}
}
'videoChannels'
]
class UserAuditView extends EntityAuditView {
- constructor (private user: User) {
+ constructor (private readonly user: User) {
super(userKeysToKeep, 'user', user)
}
}
'ownerAccount-displayedName'
]
class VideoChannelAuditView extends EntityAuditView {
- constructor (private channel: VideoChannel) {
+ constructor (private readonly channel: VideoChannel) {
super(channelKeysToKeep, 'channel', channel)
}
}
'createdAt'
]
class VideoAbuseAuditView extends EntityAuditView {
- constructor (private videoAbuse: VideoAbuse) {
+ constructor (private readonly videoAbuse: VideoAbuse) {
super(videoAbuseKeysToKeep, 'abuse', videoAbuse)
}
}
const infos: any = customConfig
const resolutionsDict = infos.transcoding.resolutions
const resolutionsArray = []
- Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => {
- if (isEnabled) resolutionsArray.push(resolution)
- })
+
+ Object.entries(resolutionsDict)
+ .forEach(([ resolution, isEnabled ]) => {
+ if (isEnabled) resolutionsArray.push(resolution)
+ })
+
Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } })
super(customConfigKeysToKeep, 'config', infos)
}
+/* eslint-disable no-useless-call */
+
/*
Different from 'utils' because we don't not import other PeerTube modules.
Useful to avoid circular dependencies.
*/
-import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto'
+import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto'
import { basename, isAbsolute, join, resolve } from 'path'
import * as pem from 'pem'
import { URL } from 'url'
const newObject = {}
Object.keys(oldObject).forEach(oldKey => {
const newKey = keyConverter(oldKey)
- newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter)
+ newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter)
})
return newObject
}
const timeTable = {
- ms: 1,
- second: 1000,
- minute: 60000,
- hour: 3600000,
- day: 3600000 * 24,
- week: 3600000 * 24 * 7,
- month: 3600000 * 24 * 30
+ ms: 1,
+ second: 1000,
+ minute: 60000,
+ hour: 3600000,
+ day: 3600000 * 24,
+ week: 3600000 * 24 * 7,
+ month: 3600000 * 24 * 30
}
export function parseDurationToMs (duration: number | string): number {
if (typeof duration === 'number') return duration
if (typeof duration === 'string') {
- const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
+ const split = duration.match(/^([\d.,]+)\s?(\w+)$/)
if (split.length === 3) {
const len = parseFloat(split[1])
- let unit = split[2].replace(/s$/i,'').toLowerCase()
+ let unit = split[2].replace(/s$/i, '').toLowerCase()
if (unit === 'm') {
unit = 'ms'
}
if (value.match(tgm)) {
match = value.match(tgm)
- return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
- + parseInt(match[2], 10) * 1024 * 1024 * 1024
- + parseInt(match[3], 10) * 1024 * 1024
+ return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 * 1024 +
+ parseInt(match[3], 10) * 1024 * 1024
} else if (value.match(tg)) {
match = value.match(tg)
- return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
- + parseInt(match[2], 10) * 1024 * 1024 * 1024
+ return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 * 1024
} else if (value.match(tm)) {
match = value.match(tm)
- return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
- + parseInt(match[2], 10) * 1024 * 1024
+ return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024
} else if (value.match(gm)) {
match = value.match(gm)
- return parseInt(match[1], 10) * 1024 * 1024 * 1024
- + parseInt(match[2], 10) * 1024 * 1024
+ return parseInt(match[1], 10) * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024
} else if (value.match(t)) {
match = value.match(t)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
}
let rootPath: string
+
function root () {
if (rootPath) return rootPath
'=': '='
}
- return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s])
+ return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
}
function pageToStartAndCount (page: number, itemsPerPage: number) {
function execShell (command: string, options?: ExecOptions) {
return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => {
exec(command, options, (err, stdout, stderr) => {
+ // eslint-disable-next-line prefer-promise-reject-errors
if (err) return rej({ err, stdout, stderr })
return res({ stdout, stderr })
}
}
-function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> {
- return function promisified (arg: T): Promise<void> {
- return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
- func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ])
- })
- }
-}
-
function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> {
return function promisified (arg1: T, arg2: U): Promise<A> {
return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
}
}
-function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> {
- return function promisified (arg1: T, arg2: U): Promise<void> {
- return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
- func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ])
- })
- }
-}
-
-const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
+const randomBytesPromise = promisify1<number, Buffer>(randomBytes)
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
const execPromise2 = promisify2<string, any, string>(exec)
promisify1,
promisify2,
- pseudoRandomBytesPromise,
+ randomBytesPromise,
createPrivateKey,
getPublicKey,
execPromise2,
const CACHE = {
'https://w3id.org/security/v1': {
'@context': {
- 'id': '@id',
- 'type': '@type',
+ id: '@id',
+ type: '@type',
- 'dc': 'http://purl.org/dc/terms/',
- 'sec': 'https://w3id.org/security#',
- 'xsd': 'http://www.w3.org/2001/XMLSchema#',
+ dc: 'http://purl.org/dc/terms/',
+ sec: 'https://w3id.org/security#',
+ xsd: 'http://www.w3.org/2001/XMLSchema#',
- 'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016',
- 'Ed25519Signature2018': 'sec:Ed25519Signature2018',
- 'EncryptedMessage': 'sec:EncryptedMessage',
- 'GraphSignature2012': 'sec:GraphSignature2012',
- 'LinkedDataSignature2015': 'sec:LinkedDataSignature2015',
- 'LinkedDataSignature2016': 'sec:LinkedDataSignature2016',
- 'CryptographicKey': 'sec:Key',
+ EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016',
+ Ed25519Signature2018: 'sec:Ed25519Signature2018',
+ EncryptedMessage: 'sec:EncryptedMessage',
+ GraphSignature2012: 'sec:GraphSignature2012',
+ LinkedDataSignature2015: 'sec:LinkedDataSignature2015',
+ LinkedDataSignature2016: 'sec:LinkedDataSignature2016',
+ CryptographicKey: 'sec:Key',
- 'authenticationTag': 'sec:authenticationTag',
- 'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm',
- 'cipherAlgorithm': 'sec:cipherAlgorithm',
- 'cipherData': 'sec:cipherData',
- 'cipherKey': 'sec:cipherKey',
- 'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' },
- 'creator': { '@id': 'dc:creator', '@type': '@id' },
- 'digestAlgorithm': 'sec:digestAlgorithm',
- 'digestValue': 'sec:digestValue',
- 'domain': 'sec:domain',
- 'encryptionKey': 'sec:encryptionKey',
- 'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
- 'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
- 'initializationVector': 'sec:initializationVector',
- 'iterationCount': 'sec:iterationCount',
- 'nonce': 'sec:nonce',
- 'normalizationAlgorithm': 'sec:normalizationAlgorithm',
- 'owner': { '@id': 'sec:owner', '@type': '@id' },
- 'password': 'sec:password',
- 'privateKey': { '@id': 'sec:privateKey', '@type': '@id' },
- 'privateKeyPem': 'sec:privateKeyPem',
- 'publicKey': { '@id': 'sec:publicKey', '@type': '@id' },
- 'publicKeyBase58': 'sec:publicKeyBase58',
- 'publicKeyPem': 'sec:publicKeyPem',
- 'publicKeyWif': 'sec:publicKeyWif',
- 'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' },
- 'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
- 'salt': 'sec:salt',
- 'signature': 'sec:signature',
- 'signatureAlgorithm': 'sec:signingAlgorithm',
- 'signatureValue': 'sec:signatureValue'
+ authenticationTag: 'sec:authenticationTag',
+ canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm',
+ cipherAlgorithm: 'sec:cipherAlgorithm',
+ cipherData: 'sec:cipherData',
+ cipherKey: 'sec:cipherKey',
+ created: { '@id': 'dc:created', '@type': 'xsd:dateTime' },
+ creator: { '@id': 'dc:creator', '@type': '@id' },
+ digestAlgorithm: 'sec:digestAlgorithm',
+ digestValue: 'sec:digestValue',
+ domain: 'sec:domain',
+ encryptionKey: 'sec:encryptionKey',
+ expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
+ expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
+ initializationVector: 'sec:initializationVector',
+ iterationCount: 'sec:iterationCount',
+ nonce: 'sec:nonce',
+ normalizationAlgorithm: 'sec:normalizationAlgorithm',
+ owner: { '@id': 'sec:owner', '@type': '@id' },
+ password: 'sec:password',
+ privateKey: { '@id': 'sec:privateKey', '@type': '@id' },
+ privateKeyPem: 'sec:privateKeyPem',
+ publicKey: { '@id': 'sec:publicKey', '@type': '@id' },
+ publicKeyBase58: 'sec:publicKeyBase58',
+ publicKeyPem: 'sec:publicKeyPem',
+ publicKeyWif: 'sec:publicKeyWif',
+ publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' },
+ revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
+ salt: 'sec:salt',
+ signature: 'sec:signature',
+ signatureAlgorithm: 'sec:signingAlgorithm',
+ signatureValue: 'sec:signatureValue'
}
}
}
const lru = new AsyncLRU({
max: 10,
load: (url, cb) => {
- if (CACHE[ url ] !== undefined) {
+ if (CACHE[url] !== undefined) {
logger.debug('Using cache for JSON-LD %s.', url)
return cb(null, {
contextUrl: null,
- document: CACHE[ url ],
+ document: CACHE[url],
documentUrl: url
})
}
import { peertubeTruncate } from '@server/helpers/core-utils'
function isActorEndpointsObjectValid (endpointObject: any) {
- if (endpointObject && endpointObject.sharedInbox) {
+ if (endpointObject?.sharedInbox) {
return isActivityPubUrlValid(endpointObject.sharedInbox)
}
actor.summary = null
}
}
-
- return
}
function isValidActorHandle (handle: string) {
if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
else comment.url = comment.id
}
-
- return
}
function isCommentTypeValid (comment: any): boolean {
if (isArray(files)) return optional
// Should have a file
- const fileArray = files[ field ]
+ const fileArray = files[field]
if (!fileArray || fileArray.length === 0) {
return optional
}
// The file should exist
- const file = fileArray[ 0 ]
+ const file = fileArray[0]
if (!file || !file.originalname) return false
// Check size
function isPluginNameValid (value: string) {
return exists(value) &&
validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) &&
- validator.matches(value, /^[a-z\-]+$/)
+ validator.matches(value, /^[a-z-]+$/)
}
function isNpmPluginNameValid (value: string) {
}
function isLibraryCodeValid (library: any) {
- return typeof library.register === 'function'
- && typeof library.unregister === 'function'
+ return typeof library.register === 'function' &&
+ typeof library.unregister === 'function'
}
export {
function isUserNotificationSettingValid (value: any) {
return exists(value) &&
- validator.isInt('' + value) && (
+ validator.isInt('' + value) &&
+ (
value === UserNotificationSettingValue.NONE ||
value === UserNotificationSettingValue.WEB ||
value === UserNotificationSettingValue.EMAIL ||
-import { Response } from 'express'
import validator from 'validator'
import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
import { exists } from './misc'
-import { VideoAbuseModel } from '../../models/video/video-abuse'
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
}
function isVideoAbuseStateValid (value: string) {
- return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined
+ return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined
}
// ---------------------------------------------------------------------------
import { exists, isFileValid } from './misc'
function isVideoCaptionLanguageValid (value: any) {
- return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined
+ return exists(value) && VIDEO_LANGUAGES[value] !== undefined
}
const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT)
}
function isVideoImportStateValid (value: any) {
- return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined
+ return exists(value) && VIDEO_IMPORT_STATES[value] !== undefined
}
const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`)
import { exists } from './misc'
import validator from 'validator'
import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants'
-import * as express from 'express'
-import { VideoPlaylistModel } from '../../models/video/video-playlist'
const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS
}
function isVideoPlaylistPrivacyValid (value: number) {
- return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[ value ] !== undefined
+ return validator.isInt(value + '') && VIDEO_PLAYLIST_PRIVACIES[value] !== undefined
}
function isVideoPlaylistTimestampValid (value: any) {
}
function isVideoPlaylistTypeValid (value: any) {
- return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined
+ return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined
}
// ---------------------------------------------------------------------------
}
function isVideoCategoryValid (value: any) {
- return value === null || VIDEO_CATEGORIES[ value ] !== undefined
+ return value === null || VIDEO_CATEGORIES[value] !== undefined
}
function isVideoStateValid (value: any) {
- return exists(value) && VIDEO_STATES[ value ] !== undefined
+ return exists(value) && VIDEO_STATES[value] !== undefined
}
function isVideoLicenceValid (value: any) {
- return value === null || VIDEO_LICENCES[ value ] !== undefined
+ return value === null || VIDEO_LICENCES[value] !== undefined
}
function isVideoLanguageValid (value: any) {
}
function isVideoPrivacyValid (value: number) {
- return VIDEO_PRIVACIES[ value ] !== undefined
+ return VIDEO_PRIVACIES[value] !== undefined
}
function isScheduleVideoUpdatePrivacyValid (value: number) {
if (paramNSFW === 'false') return false
if (paramNSFW === 'both') return undefined
- if (res && res.locals.oauth) {
+ if (res?.locals.oauth) {
const user = res.locals.oauth.token.User
// User does not want NSFW videos
return null
}
-function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) {
+function cleanUpReqFiles (req: { files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] }) {
const files = req.files
if (!files) return
}
for (const key of Object.keys(files)) {
- const file = files[ key ]
+ const file = files[key]
if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
else deleteFileAsync(file.path)
function createReqFiles (
fieldNames: string[],
- mimeTypes: { [ id: string ]: string },
- destinations: { [ fieldName: string ]: string }
+ mimeTypes: { [id: string]: string },
+ destinations: { [fieldName: string]: string }
) {
const storage = multer.diskStorage({
destination: (req, file, cb) => {
- cb(null, destinations[ file.fieldname ])
+ cb(null, destinations[file.fieldname])
},
filename: async (req, file, cb) => {
let extension: string
const fileExtension = extname(file.originalname)
- const extensionFromMimetype = mimeTypes[ file.mimetype ]
+ const extensionFromMimetype = mimeTypes[file.mimetype]
// Take the file extension if we don't understand the mime type
// We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
}
})
- let fields: { name: string, maxCount: number }[] = []
+ const fields: { name: string, maxCount: number }[] = []
for (const fieldName of fieldNames) {
fields.push({
name: fieldName,
import * as ffmpeg from 'fluent-ffmpeg'
import { dirname, join } from 'path'
-import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos'
+import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos'
import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
import { processImage } from './image-utils'
import { logger } from './logger'
import { readFile, remove, writeFile } from 'fs-extra'
import { CONFIG } from '../initializers/config'
+/**
+ * A toolbox to play with audio
+ */
+namespace audio {
+ export const get = (videoPath: string) => {
+ // without position, ffprobe considers the last input only
+ // we make it consider the first input only
+ // if you pass a file path to pos, then ffprobe acts on that file directly
+ return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => {
+
+ function parseFfprobe (err: any, data: ffmpeg.FfprobeData) {
+ if (err) return rej(err)
+
+ if ('streams' in data) {
+ const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio')
+ if (audioStream) {
+ return res({
+ absolutePath: data.format.filename,
+ audioStream
+ })
+ }
+ }
+
+ return res({ absolutePath: data.format.filename })
+ }
+
+ return ffmpeg.ffprobe(videoPath, parseFfprobe)
+ })
+ }
+
+ export namespace bitrate {
+ const baseKbitrate = 384
+
+ const toBits = (kbits: number) => kbits * 8000
+
+ export const aac = (bitrate: number): number => {
+ switch (true) {
+ case bitrate > toBits(baseKbitrate):
+ return baseKbitrate
+
+ default:
+ return -1 // we interpret it as a signal to copy the audio stream as is
+ }
+ }
+
+ export const mp3 = (bitrate: number): number => {
+ /*
+ a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
+ That's why, when using aac, we can go to lower kbit/sec. The equivalences
+ made here are not made to be accurate, especially with good mp3 encoders.
+ */
+ switch (true) {
+ case bitrate <= toBits(192):
+ return 128
+
+ case bitrate <= toBits(384):
+ return 256
+
+ default:
+ return baseKbitrate
+ }
+ }
+ }
+}
+
function computeResolutionsToTranscode (videoFileHeight: number) {
const resolutionsEnabled: number[] = []
const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
]
for (const resolution of resolutions) {
- if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) {
+ if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) {
resolutionsEnabled.push(resolution)
}
}
const videoCodec = videoStream.codec_tag_string
const baseProfileMatrix = {
- 'High': '6400',
- 'Main': '4D40',
- 'Baseline': '42E0'
+ High: '6400',
+ Main: '4D40',
+ Baseline: '42E0'
}
let baseProfile = baseProfileMatrix[videoStream.profile]
if (videoStream === null) return 0
for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
- const valuesText: string = videoStream[ key ]
+ const valuesText: string = videoStream[key]
if (!valuesText) continue
const [ frames, seconds ] = valuesText.split('/')
type: 'only-audio'
}
-type TranscodeOptions = HLSTranscodeOptions
+type TranscodeOptions =
+ HLSTranscodeOptions
| VideoTranscodeOptions
| MergeAudioTranscodeOptions
| OnlyAudioTranscodeOptions
.output(options.outputPath)
if (options.type === 'quick-transcode') {
- command = await buildQuickTranscodeCommand(command)
+ command = buildQuickTranscodeCommand(command)
} else if (options.type === 'hls') {
command = await buildHLSCommand(command, options)
} else if (options.type === 'merge-audio') {
command = await buildAudioMergeCommand(command, options)
} else if (options.type === 'only-audio') {
- command = await buildOnlyAudioCommand(command, options)
+ command = buildOnlyAudioCommand(command, options)
} else {
command = await buildx264Command(command, options)
}
// check video params
if (videoStream == null) return false
- if (videoStream[ 'codec_name' ] !== 'h264') return false
- if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false
+ if (videoStream['codec_name'] !== 'h264') return false
+ if (videoStream['pix_fmt'] !== 'yuv420p') return false
if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
// check audio params (if audio stream exists)
if (parsedAudio.audioStream) {
- if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false
+ if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
- const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ])
- if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false
+ const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate'])
+ if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false
}
return true
return command
}
-async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
- command = await presetOnlyAudio(command)
+function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
+ command = presetOnlyAudio(command)
return command
}
-async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
- command = await presetCopy(command)
+function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
+ command = presetCopy(command)
command = command.outputOption('-map_metadata -1') // strip all metadata
.outputOption('-movflags faststart')
async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
const videoPath = getHLSVideoPath(options)
- if (options.copyCodecs) command = await presetCopy(command)
+ if (options.copyCodecs) command = presetCopy(command)
else command = await buildx264Command(command, options)
command = command.outputOption('-hls_time 4')
return localCommand
}
-/**
- * A toolbox to play with audio
- */
-namespace audio {
- export const get = (videoPath: string) => {
- // without position, ffprobe considers the last input only
- // we make it consider the first input only
- // if you pass a file path to pos, then ffprobe acts on that file directly
- return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => {
-
- function parseFfprobe (err: any, data: ffmpeg.FfprobeData) {
- if (err) return rej(err)
-
- if ('streams' in data) {
- const audioStream = data.streams.find(stream => stream[ 'codec_type' ] === 'audio')
- if (audioStream) {
- return res({
- absolutePath: data.format.filename,
- audioStream
- })
- }
- }
-
- return res({ absolutePath: data.format.filename })
- }
-
- return ffmpeg.ffprobe(videoPath, parseFfprobe)
- })
- }
-
- export namespace bitrate {
- const baseKbitrate = 384
-
- const toBits = (kbits: number) => kbits * 8000
-
- export const aac = (bitrate: number): number => {
- switch (true) {
- case bitrate > toBits(baseKbitrate):
- return baseKbitrate
-
- default:
- return -1 // we interpret it as a signal to copy the audio stream as is
- }
- }
-
- export const mp3 = (bitrate: number): number => {
- /*
- a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
- That's why, when using aac, we can go to lower kbit/sec. The equivalences
- made here are not made to be accurate, especially with good mp3 encoders.
- */
- switch (true) {
- case bitrate <= toBits(192):
- return 128
-
- case bitrate <= toBits(384):
- return 256
-
- default:
- return baseKbitrate
- }
- }
- }
-}
-
/**
* Standard profile, with variable bitrate audio and faststart.
*
// of course this is far from perfect, but it might save some space in the end
localCommand = localCommand.audioCodec('aac')
- const audioCodecName = parsedAudio.audioStream[ 'codec_name' ]
+ const audioCodecName = parsedAudio.audioStream['codec_name']
- if (audio.bitrate[ audioCodecName ]) {
- const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ])
+ if (audio.bitrate[audioCodecName]) {
+ const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate'])
if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
}
}
return localCommand
}
-async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
+function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
return command
.format('mp4')
.videoCodec('copy')
.audioCodec('copy')
}
-async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
+function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
return command
.format('mp4')
.audioCodec('copy')
if (value instanceof Error) {
const error = {}
- Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ])
+ Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
return error
}
let args: any[] = []
args.concat(arguments)
- if (arguments[ 0 ] instanceof Error) {
- meta = arguments[ 0 ].toString()
+ if (arguments[0] instanceof Error) {
+ meta = arguments[0].toString()
args = Array.prototype.slice.call(arguments, 1)
args.push(meta)
- } else if (typeof (args[ 0 ]) !== 'string') {
- meta = arguments[ 0 ]
+ } else if (typeof (args[0]) !== 'string') {
+ meta = arguments[0]
args = Array.prototype.slice.call(arguments, 1)
args.push(meta)
}
- logger[ level ].apply(logger, args)
+ logger[level].apply(logger, args)
}
}
+
const bunyanLogger = {
trace: bunyanLogFactory('debug'),
debug: bunyanLogFactory('debug'),
// Thanks to https://regex101.com
function regexpCapture (str: string, regex: RegExp, maxIterations = 100) {
+ const result: RegExpExecArray[] = []
let m: RegExpExecArray
let i = 0
- let result: RegExpExecArray[] = []
// tslint:disable:no-conditional-assignment
while ((m = regex.exec(str)) !== null && i < maxIterations) {
import { resolve } from 'path'
-const tsConfigPaths = require('tsconfig-paths')
+import tsConfigPaths = require('tsconfig-paths')
const tsConfig = require('../../tsconfig.json')
function isSignupAllowedForCurrentIP (ip: string) {
const addr = ipaddr.parse(ip)
- let excludeList = [ 'blacklist' ]
+ const excludeList = [ 'blacklist' ]
let matched = ''
// if there is a valid, non-empty whitelist, we exclude all unknown adresses too
import { ResultList } from '../../shared'
import { ApplicationModel } from '../models/application/application'
-import { execPromise, execPromise2, pseudoRandomBytesPromise, sha256 } from './core-utils'
+import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils'
import { logger } from './logger'
import { join } from 'path'
import { Instance as ParseTorrent } from 'parse-torrent'
}
async function generateRandomString (size: number) {
- const raw = await pseudoRandomBytesPromise(size)
+ const raw = await randomBytesPromise(size)
return raw.toString('hex')
}
if (torrent.files.length !== 1) {
if (timer) clearTimeout(timer)
- for (let file of torrent.files) {
+ for (const file of torrent.files) {
deleteDownloadedFile({ directoryPath, filepath: file.path })
}
.then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it')))
}
- file = torrent.files[ 0 ]
+ file = torrent.files[0]
// FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed
const writeStream = createWriteStream(path)
writeStream.on('finish', () => {
if (timer) clearTimeout(timer)
- return safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName)
+ safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName)
.then(() => res(path))
+ .catch(err => logger.error('Cannot destroy webtorrent.', { err }))
})
file.createReadStream().pipe(writeStream)
torrent.on('error', err => rej(err))
- timer = setTimeout(async () => {
- return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName)
- .then(() => rej(new Error('Webtorrent download timeout.')))
+ timer = setTimeout(() => {
+ const err = new Error('Webtorrent download timeout.')
+
+ safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName)
+ .then(() => rej(err))
+ .catch(destroyErr => {
+ logger.error('Cannot destroy webtorrent.', { err: destroyErr })
+ rej(err)
+ })
+
}, timeout)
})
}
}
function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> {
- return new Promise<YoutubeDLInfo>(async (res, rej) => {
+ return new Promise<YoutubeDLInfo>((res, rej) => {
let args = opts || [ '-j', '--flat-playlist' ]
args = wrapWithProxyOptions(args)
- const youtubeDL = await safeGetYoutubeDL()
- youtubeDL.getInfo(url, args, processOptions, (err, info) => {
- if (err) return rej(err)
- if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
+ safeGetYoutubeDL()
+ .then(youtubeDL => {
+ youtubeDL.getInfo(url, args, processOptions, (err, info) => {
+ if (err) return rej(err)
+ if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
- const obj = buildVideoInfo(normalizeObject(info))
- if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video'
+ const obj = buildVideoInfo(normalizeObject(info))
+ if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video'
- return res(obj)
- })
+ return res(obj)
+ })
+ })
+ .catch(err => rej(err))
})
}
options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ])
}
- return new Promise<string>(async (res, rej) => {
- const youtubeDL = await safeGetYoutubeDL()
- youtubeDL.exec(url, options, processOptions, err => {
- clearTimeout(timer)
+ return new Promise<string>((res, rej) => {
+ safeGetYoutubeDL()
+ .then(youtubeDL => {
+ youtubeDL.exec(url, options, processOptions, err => {
+ clearTimeout(timer)
- if (err) {
- remove(path)
- .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err }))
+ if (err) {
+ remove(path)
+ .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err }))
- return rej(err)
- }
+ return rej(err)
+ }
- return res(path)
- })
+ return res(path)
+ })
- timer = setTimeout(async () => {
- await remove(path)
+ timer = setTimeout(() => {
+ const err = new Error('YoutubeDL download timeout.')
- return rej(new Error('YoutubeDL download timeout.'))
- }, timeout)
+ remove(path)
+ .finally(() => rej(err))
+ .catch(err => {
+ logger.error('Cannot remove %s in youtubeDL timeout.', path, { err })
+ return rej(err)
+ })
+ }, timeout)
+ })
+ .catch(err => rej(err))
})
}
const url = result.headers.location
const downloadFile = request.get(url)
- const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ]
+ const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1]
downloadFile.on('response', result => {
if (result.statusCode !== 200) {
import { UserModel } from '../models/account/user'
import { ApplicationModel } from '../models/application/application'
import { OAuthClientModel } from '../models/oauth/oauth-client'
-import { parse } from 'url'
+import { URL } from 'url'
import { CONFIG } from './config'
import { logger } from '../helpers/logger'
import { getServerActor } from '../helpers/utils'
async function checkActivityPubUrls () {
const actor = await getServerActor()
- const parsed = parse(actor.url)
+ const parsed = new URL(actor.url)
if (WEBSERVER.HOST !== parsed.host) {
const NODE_ENV = config.util.getEnv('NODE_ENV')
const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')
]
const requiredAlternatives = [
[ // set
- ['redis.hostname', 'redis.port'], // alternative
- ['redis.socket']
+ [ 'redis.hostname', 'redis.port' ], // alternative
+ [ 'redis.socket' ]
]
]
const miss: string[] = []
if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
- return join(dirname(configSources[ 0 ].name), filename + '.json')
+ return join(dirname(configSources[0].name), filename + '.json')
}
function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
function purge () {
for (const fileName in require.cache) {
- if (-1 === fileName.indexOf(directory())) {
+ if (fileName.indexOf(directory()) === -1) {
continue
}
import { FollowState } from '../../shared/models/actors'
import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
// Do not use barrels, remain constants as independent as possible
-import { isTestInstance, sanitizeHost, sanitizeUrl, root, parseDurationToMs } from '../helpers/core-utils'
+import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils'
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
import { invert } from 'lodash'
import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
MIN: 10,
- STANDARD: [24, 25, 30],
- HD_STANDARD: [50, 60],
+ STANDARD: [ 24, 25, 30 ],
+ HD_STANDARD: [ 50, 60 ],
AVERAGE: 30,
MAX: 60,
KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
7: 'Public Domain Dedication'
}
-let VIDEO_LANGUAGES: { [id: string]: string } = {}
+const VIDEO_LANGUAGES: { [id: string]: string } = {}
const VIDEO_PRIVACIES = {
- [ VideoPrivacy.PUBLIC ]: 'Public',
- [ VideoPrivacy.UNLISTED ]: 'Unlisted',
- [ VideoPrivacy.PRIVATE ]: 'Private',
- [ VideoPrivacy.INTERNAL ]: 'Internal'
+ [VideoPrivacy.PUBLIC]: 'Public',
+ [VideoPrivacy.UNLISTED]: 'Unlisted',
+ [VideoPrivacy.PRIVATE]: 'Private',
+ [VideoPrivacy.INTERNAL]: 'Internal'
}
const VIDEO_STATES = {
- [ VideoState.PUBLISHED ]: 'Published',
- [ VideoState.TO_TRANSCODE ]: 'To transcode',
- [ VideoState.TO_IMPORT ]: 'To import'
+ [VideoState.PUBLISHED]: 'Published',
+ [VideoState.TO_TRANSCODE]: 'To transcode',
+ [VideoState.TO_IMPORT]: 'To import'
}
const VIDEO_IMPORT_STATES = {
- [ VideoImportState.FAILED ]: 'Failed',
- [ VideoImportState.PENDING ]: 'Pending',
- [ VideoImportState.SUCCESS ]: 'Success'
+ [VideoImportState.FAILED]: 'Failed',
+ [VideoImportState.PENDING]: 'Pending',
+ [VideoImportState.SUCCESS]: 'Success'
}
const VIDEO_ABUSE_STATES = {
- [ VideoAbuseState.PENDING ]: 'Pending',
- [ VideoAbuseState.REJECTED ]: 'Rejected',
- [ VideoAbuseState.ACCEPTED ]: 'Accepted'
+ [VideoAbuseState.PENDING]: 'Pending',
+ [VideoAbuseState.REJECTED]: 'Rejected',
+ [VideoAbuseState.ACCEPTED]: 'Accepted'
}
const VIDEO_PLAYLIST_PRIVACIES = {
- [ VideoPlaylistPrivacy.PUBLIC ]: 'Public',
- [ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted',
- [ VideoPlaylistPrivacy.PRIVATE ]: 'Private'
+ [VideoPlaylistPrivacy.PUBLIC]: 'Public',
+ [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
+ [VideoPlaylistPrivacy.PRIVATE]: 'Private'
}
const VIDEO_PLAYLIST_TYPES = {
- [ VideoPlaylistType.REGULAR ]: 'Regular',
- [ VideoPlaylistType.WATCH_LATER ]: 'Watch later'
+ [VideoPlaylistType.REGULAR]: 'Regular',
+ [VideoPlaylistType.WATCH_LATER]: 'Watch later'
}
const MIMETYPES = {
}
// Cache control
-let STATIC_MAX_AGE = {
+const STATIC_MAX_AGE = {
SERVER: '2h',
CLIENT: '30d'
}
SCHEDULER_INTERVALS_MS.removeOldViews = 5000
SCHEDULER_INTERVALS_MS.updateVideos = 5000
SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000
- REPEAT_JOBS[ 'videos-views' ] = { every: 5000 }
+ REPEAT_JOBS['videos-views'] = { every: 5000 }
REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1
VIDEO_VIEW_LIFETIME = 1000 // 1 second
CONTACT_FORM_LIFETIME = 1000 // 1 second
- JOB_ATTEMPTS[ 'email' ] = 1
+ JOB_ATTEMPTS['email'] = 1
FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000
MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1
function buildLanguages () {
const iso639 = require('iso-639-3')
- const languages: { [ id: string ]: string } = {}
+ const languages: { [id: string]: string } = {}
const additionalLanguages = {
- 'sgn': true, // Sign languages (macro language)
- 'ase': true, // American sign language
- 'sdl': true, // Arabian sign language
- 'bfi': true, // British sign language
- 'bzs': true, // Brazilian sign language
- 'csl': true, // Chinese sign language
- 'cse': true, // Czech sign language
- 'dsl': true, // Danish sign language
- 'fsl': true, // French sign language
- 'gsg': true, // German sign language
- 'pks': true, // Pakistan sign language
- 'jsl': true, // Japanese sign language
- 'sfs': true, // South African sign language
- 'swl': true, // Swedish sign language
- 'rsl': true, // Russian sign language: true
-
- 'epo': true, // Esperanto
- 'tlh': true, // Klingon
- 'jbo': true, // Lojban
- 'avk': true // Kotava
+ sgn: true, // Sign languages (macro language)
+ ase: true, // American sign language
+ sdl: true, // Arabian sign language
+ bfi: true, // British sign language
+ bzs: true, // Brazilian sign language
+ csl: true, // Chinese sign language
+ cse: true, // Czech sign language
+ dsl: true, // Danish sign language
+ fsl: true, // French sign language
+ gsg: true, // German sign language
+ pks: true, // Pakistan sign language
+ jsl: true, // Japanese sign language
+ sfs: true, // South African sign language
+ swl: true, // Swedish sign language
+ rsl: true, // Russian sign language: true
+
+ epo: true, // Esperanto
+ tlh: true, // Klingon
+ jbo: true, // Lojban
+ avk: true // Kotava
}
// Only add ISO639-1 languages and some sign languages (ISO639-3)
iso639
.filter(l => {
return (l.iso6391 !== null && l.type === 'living') ||
- additionalLanguages[ l.iso6393 ] === true
+ additionalLanguages[l.iso6393] === true
})
- .forEach(l => languages[ l.iso6391 || l.iso6393 ] = l.name)
+ .forEach(l => { languages[l.iso6391 || l.iso6393] = l.name })
// Override Occitan label
- languages[ 'oc' ] = 'Occitan'
- languages[ 'el' ] = 'Greek'
+ languages['oc'] = 'Occitan'
+ languages['el'] = 'Greek'
return languages
}
await createFunctions()
if (!silent) logger.info('Database %s is ready.', dbname)
-
- return
}
// ---------------------------------------------------------------------------
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import { getVideoFilePath } from '@server/lib/video-paths'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
return utils.db.Video.listOwnedAndPopulateAuthorAndTags()
import { Migration } from '../../models/migrations'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import { readdir, rename } from 'fs-extra'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const torrentDir = CONFIG.STORAGE.TORRENTS_DIR
import * as uuidv4 from 'uuid/v4'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import { SERVER_ACTOR_NAME } from '../constants'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const q = utils.queryInterface
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
await utils.queryInterface.removeColumn('Servers', 'email')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
await utils.queryInterface.removeColumn('Servers', 'publicKey')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
await utils.db.Avatar.sync()
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
await utils.queryInterface.renameTable('Applications', 'application')
import * as Promise from 'bluebird'
function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const q = utils.queryInterface
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
// Create actor table
type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
)
- SELECT
+ SELECT
'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
- "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
- FROM account
+ "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
+ FROM account
WHERE "applicationId" IS NOT NULL
`
await utils.sequelize.query(query1)
type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
)
- SELECT
+ SELECT
'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
- "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
- FROM account
+ "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
+ FROM account
WHERE "applicationId" IS NULL
`
await utils.sequelize.query(query2)
}
{
- const query = `
- INSERT INTO actor
+ const query = `
+ INSERT INTO actor
(
- type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
+ type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
"sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
)
- SELECT
- 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox',
+ SELECT
+ 'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox',
"videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following',
- null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt"
- FROM "videoChannel"
+ null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt"
+ FROM "videoChannel"
INNER JOIN "account" on "videoChannel"."accountId" = "account".id
`
await utils.sequelize.query(query)
}
{
- const query1 = `UPDATE "actorFollow"
- SET "actorId" =
+ const query1 = `UPDATE "actorFollow"
+ SET "actorId" =
(SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")`
await utils.sequelize.query(query1)
- const query2 = `UPDATE "actorFollow"
- SET "targetActorId" =
+ const query2 = `UPDATE "actorFollow"
+ SET "targetActorId" =
(SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")`
await utils.sequelize.query(query2)
await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey')
}
- const query = `UPDATE "videoShare"
- SET "actorId" =
+ const query = `UPDATE "videoShare"
+ SET "actorId" =
(SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")`
await utils.sequelize.query(query)
import { WEBSERVER } from '../constants'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const toReplace = WEBSERVER.HOSTNAME + ':443'
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
await utils.queryInterface.dropTable('Authors')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey')
import { Migration } from '../../models/migrations'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import { ACTOR_FOLLOW_SCORE } from '../constants'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
await utils.queryInterface.removeColumn('server', 'score')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const query = 'UPDATE "actor" SET ' +
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
await utils.queryInterface.dropTable('job')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import { CONSTRAINTS_FIELDS } from '../constants'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
-import { VideoAbuseState } from '../../../shared/models/videos'
async function up (utils: {
transaction: Sequelize.Transaction
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const indexNames = [
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import { Migration } from '../../models/migrations'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
import { WEBSERVER } from '../constants'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize
}): Promise<void> {
const transaction = utils.transaction
import { VideoBlacklistType } from '../../../shared/models/videos'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
try {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
await utils.queryInterface.removeColumn('actor', 'uuid')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
const data = {
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
-import { join } from 'path'
-import { HLS_STREAMING_PLAYLIST_DIRECTORY, WEBSERVER } from '@server/initializers/constants'
-import { CONFIG } from '@server/initializers/config'
-import { pathExists, stat, writeFile } from 'fs-extra'
-import * as parseTorrent from 'parse-torrent'
-import { createTorrentPromise } from '@server/helpers/webtorrent'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
{
const query = 'insert into "videoFile" ' +
'(resolution, size, "infoHash", "videoId", "createdAt", "updatedAt", fps, extname, "videoStreamingPlaylistId")' +
- '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", "videoFile"."fps", ' +
- '"videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' +
+ '(SELECT "videoFile".resolution, "videoFile".size, \'fake\', NULL, "videoFile"."createdAt", "videoFile"."updatedAt", ' +
+ '"videoFile"."fps", "videoFile".extname, "videoStreamingPlaylist".id FROM "videoStreamingPlaylist" ' +
'inner join video ON video.id = "videoStreamingPlaylist"."videoId" inner join "videoFile" ON "videoFile"."videoId" = video.id)'
await utils.sequelize.query(query, { transaction: utils.transaction })
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
await utils.sequelize.query('DROP INDEX IF EXISTS video_share_account_id;')
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
import * as Sequelize from 'sequelize'
async function up (utils: {
- transaction: Sequelize.Transaction,
- queryInterface: Sequelize.QueryInterface,
- sequelize: Sequelize.Sequelize,
+ transaction: Sequelize.Transaction
+ queryInterface: Sequelize.QueryInterface
+ sequelize: Sequelize.Sequelize
db: any
}): Promise<void> {
{
}
const rows = await sequelizeTypescript.query<{ migrationVersion: number }>(query, options)
- if (rows && rows[0] && rows[0].migrationVersion) {
+ if (rows?.[0]?.migrationVersion) {
actualVersion = rows[0].migrationVersion
}
async function getMigrationScripts () {
const files = await readdir(path.join(__dirname, 'migrations'))
const filesToMigrate: {
- version: string,
+ version: string
script: string
}[] = []
import * as Bluebird from 'bluebird'
import { Transaction } from 'sequelize'
-import * as url from 'url'
+import { URL } from 'url'
import * as uuidv4 from 'uuid/v4'
import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub'
import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects'
MActorFull,
MActorFullActor,
MActorId,
- MChannel,
- MChannelAccountDefault
+ MChannel
} from '../../typings/models'
// Set account keys, this could be long so process after the account creation and do not block the client
if ((created === true || refreshed === true) && updateCollections === true) {
const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' }
- await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
+ await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })
}
// We created a new account: fetch the playlists
if (created === true && actor.Account && accountPlaylistsUrl) {
const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' }
- await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
+ await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload })
}
return actorRefreshed
}
}
-async function getAvatarInfoIfExists (actorJSON: ActivityPubActor) {
+function getAvatarInfoIfExists (actorJSON: ActivityPubActor) {
if (
actorJSON.icon && actorJSON.icon.type === 'Image' && MIMETYPES.IMAGE.MIMETYPE_EXT[actorJSON.icon.mediaType] !== undefined &&
isActivityPubUrlValid(actorJSON.icon.url)
if (statusCode === 404) {
logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url)
- actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy()
+ actor.Account
+ ? await actor.Account.destroy()
+ : await actor.VideoChannel.destroy()
+
return { actor: undefined, refreshed: false }
}
ownerActor?: MActorFullActor,
t?: Transaction
): Bluebird<MActorFullActor> | Promise<MActorFullActor> {
- let actor = result.actor
+ const actor = result.actor
if (t !== undefined) return save(t)
return sequelizeTypescript.transaction(t => save(t))
async function save (t: Transaction) {
- const actorHost = url.parse(actor.url).host
+ const actorHost = new URL(actor.url).host
const serverOptions = {
where: {
support?: string
playlists?: string
avatar?: {
- name: string,
+ name: string
fileUrl: string
}
attributedTo: ActivityPubAttributedTo[]
import { logger } from '../../helpers/logger'
import * as Bluebird from 'bluebird'
import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub'
-import { parse } from 'url'
+import { URL } from 'url'
type HandlerFunction<T> = (items: T[]) => (Promise<any> | Bluebird<any>)
type CleanerFunction = (startedDate: Date) => (Promise<any> | Bluebird<any>)
const response = await doRequest<ActivityPubOrderedCollection<T>>(options)
const firstBody = response.body
- let limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT
+ const limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT
let i = 0
let nextLink = firstBody.first
while (nextLink && i < limit) {
if (typeof nextLink === 'string') {
// Don't crawl ourselves
- const remoteHost = parse(nextLink).host
+ const remoteHost = new URL(nextLink).host
if (remoteHost === WEBSERVER.HOST) continue
options.uri = nextLink
}
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
- .catch(err => logger.error('Cannot create auto follow back job for %s.', host, err))
}
}
import { logger } from '../../../helpers/logger'
import { MActor, MActorFollowActors } from '../../../typings/models'
-async function sendAccept (actorFollow: MActorFollowActors) {
+function sendAccept (actorFollow: MActorFollowActors) {
const follower = actorFollow.ActorFollower
const me = actorFollow.ActorFollowing
// ---------------------------------------------------------------------------
async function sendVideoRelatedCreateActivity (options: {
- byActor: MActorLight,
- video: MVideoAccountLight,
- url: string,
- object: any,
+ byActor: MActorLight
+ video: MVideoAccountLight
+ url: string
+ object: any
transaction?: Transaction
}) {
const activityBuilder = (audience: ActivityAudience) => {
import { audiencify, getAudience } from '../audience'
import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
-async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
+function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
logger.info('Creating job to dislike %s.', video.url)
const activityBuilder = (audience: ActivityAudience) => {
import { MActor, MVideoFullLight } from '../../../typings/models'
import { MVideoAbuseVideo } from '../../../typings/models/video'
-async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) {
+function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) {
if (!video.VideoChannel.Account.Actor.serverId) return // Local user
const url = getVideoAbuseActivityPubUrl(videoAbuse)
import { logger } from '../../../helpers/logger'
import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
-async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
+function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
logger.info('Creating job to like %s.', video.url)
const activityBuilder = (audience: ActivityAudience) => {
import { logger } from '../../../helpers/logger'
import { MActor } from '../../../typings/models'
-async function sendReject (follower: MActor, following: MActor) {
+function sendReject (follower: MActor, following: MActor) {
if (!follower.serverId) { // This should never happen
logger.warn('Do not sending reject to local follower.')
return
MVideoShare
} from '../../../typings/models'
-async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
+function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
const me = actorFollow.ActorFollower
const following = actorFollow.ActorFollowing
}
async function sendUndoVideoRelatedActivity (options: {
- byActor: MActor,
- video: MVideoAccountLight,
- url: string,
- activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce,
+ byActor: MActor
+ video: MVideoAccountLight
+ url: string
+ activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce
transaction: Transaction
}) {
const activityBuilder = (audience: ActivityAudience) => {
import { broadcastToFollowers, sendVideoRelatedActivity } from './utils'
import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience'
import { logger } from '../../../helpers/logger'
-import { VideoCaptionModel } from '../../../models/video/video-caption'
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
import { getServerActor } from '../../../helpers/utils'
import {
logger.info('Creating job to update video %s.', video.url)
- const byActor = overrodeByActor ? overrodeByActor : video.VideoChannel.Account.Actor
+ const byActor = overrodeByActor || video.VideoChannel.Account.Actor
const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString())
import { MActorWithInboxes, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models'
async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
- byActor: MActorLight,
- video: MVideoAccountLight,
+ byActor: MActorLight
+ video: MVideoAccountLight
transaction?: Transaction
}) {
const { byActor, video, transaction } = options
import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video'
type ResolveThreadParams = {
- url: string,
- comments?: MCommentOwner[],
- isVideo?: boolean,
+ url: string
+ comments?: MCommentOwner[]
+ isVideo?: boolean
commentCreated?: boolean
}
type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }>
if (params.commentCreated === undefined) params.commentCreated = false
if (params.comments === undefined) params.comments = []
- // Already have this comment?
+ // Already have this comment?
if (isVideo !== true) {
const result = await resolveCommentFromDB(params)
if (result) return result
let resultComment: MCommentOwnerVideo
if (comments.length !== 0) {
- const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo
+ const firstReply = comments[comments.length - 1] as MCommentOwnerVideo
firstReply.inReplyToCommentId = null
firstReply.originCommentId = null
firstReply.videoId = video.id
comments[comments.length - 1] = await firstReply.save()
for (let i = comments.length - 2; i >= 0; i--) {
- const comment = comments[ i ] as MCommentOwnerVideo
+ const comment = comments[i] as MCommentOwnerVideo
comment.originCommentId = firstReply.id
- comment.inReplyToCommentId = comments[ i + 1 ].id
+ comment.inReplyToCommentId = comments[i + 1].id
comment.videoId = video.id
comment.changed('updatedAt', true)
comment.Video = video
const field = rate === 'like' ? 'likes' : 'dislikes'
await video.increment(field, { by: rateCounts })
}
-
- return
}
async function sendVideoRateChange (
jobPayloads.push({ uri: fetchedVideo.comments, videoId: video.id, type: 'video-comments' as 'video-comments' })
}
- await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }))
+ await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }))
}
function getOrCreateVideoAndAccountAndChannel (options: {
- videoObject: { id: string } | string,
- syncParam?: SyncParam,
- fetchType?: 'all',
+ videoObject: { id: string } | string
+ syncParam?: SyncParam
+ fetchType?: 'all'
allowRefresh?: boolean
}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, created: boolean, autoBlacklisted?: boolean }>
function getOrCreateVideoAndAccountAndChannel (options: {
- videoObject: { id: string } | string,
- syncParam?: SyncParam,
- fetchType?: VideoFetchByUrlType,
+ videoObject: { id: string } | string
+ syncParam?: SyncParam
+ fetchType?: VideoFetchByUrlType
allowRefresh?: boolean
}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }>
async function getOrCreateVideoAndAccountAndChannel (options: {
- videoObject: { id: string } | string,
- syncParam?: SyncParam,
- fetchType?: VideoFetchByUrlType,
+ videoObject: { id: string } | string
+ syncParam?: SyncParam
+ fetchType?: VideoFetchByUrlType
allowRefresh?: boolean // true by default
}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> {
// Default params
syncParam
}
- if (syncParam.refreshVideo === true) videoFromDatabase = await refreshVideoIfNeeded(refreshOptions)
- else await JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: videoFromDatabase.url } })
+ if (syncParam.refreshVideo === true) {
+ videoFromDatabase = await refreshVideoIfNeeded(refreshOptions)
+ } else {
+ await JobQueue.Instance.createJobWithPromise({
+ type: 'activitypub-refresher',
+ payload: { type: 'video', url: videoFromDatabase.url }
+ })
+ }
}
return { video: videoFromDatabase, created: false }
}
async function updateVideoFromAP (options: {
- video: MVideoAccountLightBlacklistAllFiles,
- videoObject: VideoTorrentObject,
- account: MAccountIdActor,
- channel: MChannelDefault,
+ video: MVideoAccountLightBlacklistAllFiles
+ videoObject: VideoTorrentObject
+ account: MAccountIdActor
+ channel: MChannelDefault
overrideTo?: string[]
}) {
const { video, videoObject, account, channel, overrideTo } = options
throw new Error('Account ' + account.Actor.url + ' does not own video channel ' + videoChannel.Actor.url)
}
- const to = overrideTo ? overrideTo : videoObject.to
+ const to = overrideTo || videoObject.to
const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, to)
video.name = videoData.name
video.uuid = videoData.uuid
}
async function refreshVideoIfNeeded (options: {
- video: MVideoThumbnail,
- fetchedType: VideoFetchByUrlType,
+ video: MVideoThumbnail
+ fetchedType: VideoFetchByUrlType
syncParam: SyncParam
}): Promise<MVideoThumbnail> {
if (!options.video.isOutdated()) return options.video
thumbnailModel = videoCreated.id
return thumbnailModel.save()
- })
+ }).catch(err => logger.error('Cannot create miniature from url.', { err }))
}
return { autoBlacklisted, videoCreated }
}
-async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) {
+function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) {
const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
const duration = videoObject.duration.replace(/[^\d]+/, '')
const mediaType = fileUrl.mediaType
const attribute = {
- extname: MIMETYPES.VIDEO.MIMETYPE_EXT[ mediaType ],
+ extname: MIMETYPES.VIDEO.MIMETYPE_EXT[mediaType],
infoHash: parsed.infoHash,
resolution: fileUrl.height,
size: fileUrl.size,
export class ClientHtml {
- private static htmlCache: { [ path: string ]: string } = {}
+ private static htmlCache: { [path: string]: string } = {}
static invalidCache () {
logger.info('Cleaning HTML cache.')
private static async getIndexHTML (req: express.Request, res: express.Response, paramLang?: string) {
const path = ClientHtml.getIndexPath(req, res, paramLang)
- if (ClientHtml.htmlCache[ path ]) return ClientHtml.htmlCache[ path ]
+ if (ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
const buffer = await readFile(path)
html = ClientHtml.addCustomCSS(html)
html = await ClientHtml.addAsyncPluginCSS(html)
- ClientHtml.htmlCache[ path ] = html
+ ClientHtml.htmlCache[path] = html
return html
}
const schemaTags = {
'@context': 'http://schema.org',
'@type': 'VideoObject',
- name: videoNameEscaped,
- description: videoDescriptionEscaped,
- thumbnailUrl: previewUrl,
- uploadDate: video.createdAt.toISOString(),
- duration: getActivityStreamDuration(video.duration),
- contentUrl: videoUrl,
- embedUrl: embedUrl,
- interactionCount: video.views
+ 'name': videoNameEscaped,
+ 'description': videoDescriptionEscaped,
+ 'thumbnailUrl': previewUrl,
+ 'uploadDate': video.createdAt.toISOString(),
+ 'duration': getActivityStreamDuration(video.duration),
+ 'contentUrl': videoUrl,
+ 'embedUrl': embedUrl,
+ 'interactionCount': video.views
}
let tagsString = ''
// Opengraph
Object.keys(openGraphMetaTags).forEach(tagName => {
- const tagValue = openGraphMetaTags[ tagName ]
+ const tagValue = openGraphMetaTags[tagName]
tagsString += `<meta property="${tagName}" content="${tagValue}" />`
})
private initialized = false
private transporter: Transporter
- private constructor () {}
+ private constructor () {
+ }
init () {
// Already initialized
const channelName = video.VideoChannel.getDisplayName()
const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`Your subscription ${channelName} just published a new video: ${video.name}` +
- `\n\n` +
+ '\n\n' +
`You can view it on ${videoUrl} ` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
const followerName = actorFollow.ActorFollower.Account.getDisplayName()
const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`Your ${followType} ${followingName} has a new subscriber: ${followerName}` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) {
const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : ''
- const text = `Hi dear admin,\n\n` +
+ const text = 'Hi dear admin,\n\n' +
`Your instance has a new follower: ${actorFollow.ActorFollower.url}${awaitingApproval}` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
}
addAutoInstanceFollowingNotification (to: string[], actorFollow: MActorFollowActors) {
- const text = `Hi dear admin,\n\n` +
+ const text = 'Hi dear admin,\n\n' +
`Your instance automatically followed a new instance: ${actorFollow.ActorFollowing.url}` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
myVideoPublishedNotification (to: string[], video: MVideo) {
const videoUrl = WEBSERVER.URL + video.getWatchStaticPath()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`Your video ${video.name} has been published.` +
- `\n\n` +
+ '\n\n' +
`You can view it on ${videoUrl} ` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) {
const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`Your video import ${videoImport.getTargetIdentifier()} is finished.` +
- `\n\n` +
+ '\n\n' +
`You can view the imported video on ${videoUrl} ` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) {
const importUrl = WEBSERVER.URL + '/my-account/video-imports'
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`Your video import ${videoImport.getTargetIdentifier()} encountered an error.` +
- `\n\n` +
+ '\n\n' +
`See your videos import dashboard for more information: ${importUrl}` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
const video = comment.Video
const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`A new comment has been posted by ${accountName} on your video ${video.name}` +
- `\n\n` +
+ '\n\n' +
`You can view it on ${commentUrl} ` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
const video = comment.Video
const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath()
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`${accountName} mentioned you on video ${video.name}` +
- `\n\n` +
+ '\n\n' +
`You can view the comment on ${commentUrl} ` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) {
const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath()
- const text = `Hi,\n\n` +
+ const text = 'Hi,\n\n' +
`${WEBSERVER.HOST} received an abuse for the following video ${videoUrl}\n\n` +
- `Cheers,\n` +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list'
const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath()
- const text = `Hi,\n\n` +
- `A recently added video was auto-blacklisted and requires moderator review before publishing.` +
- `\n\n` +
+ const text = 'Hi,\n\n' +
+ 'A recently added video was auto-blacklisted and requires moderator review before publishing.' +
+ '\n\n' +
`You can view it and take appropriate action on ${videoUrl}` +
- `\n\n` +
+ '\n\n' +
`A full list of auto-blacklisted videos can be reviewed here: ${VIDEO_AUTO_BLACKLIST_URL}` +
- `\n\n` +
- `Cheers,\n` +
+ '\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
}
addNewUserRegistrationNotification (to: string[], user: MUser) {
- const text = `Hi,\n\n` +
+ const text = 'Hi,\n\n' +
`User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` +
- `Cheers,\n` +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
}
addPasswordResetEmailJob (to: string, resetPasswordUrl: string) {
- const text = `Hi dear user,\n\n` +
+ const text = 'Hi dear user,\n\n' +
`A reset password procedure for your account ${to} has been requested on ${WEBSERVER.HOST} ` +
`Please follow this link to reset it: ${resetPasswordUrl} (the link will expire within 1 hour)\n\n` +
- `If you are not the person who initiated this request, please ignore this email.\n\n` +
- `Cheers,\n` +
+ 'If you are not the person who initiated this request, please ignore this email.\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
}
addVerifyEmailJob (to: string, verifyEmailUrl: string) {
- const text = `Welcome to PeerTube,\n\n` +
+ const text = 'Welcome to PeerTube,\n\n' +
`To start using PeerTube on ${WEBSERVER.HOST} you must verify your email! ` +
`Please follow this link to verify this email belongs to you: ${verifyEmailUrl}\n\n` +
- `If you are not the person who initiated this request, please ignore this email.\n\n` +
- `Cheers,\n` +
+ 'If you are not the person who initiated this request, please ignore this email.\n\n' +
+ 'Cheers,\n' +
`${CONFIG.EMAIL.BODY.SIGNATURE}`
const emailPayload: EmailPayload = {
import { join } from 'path'
-import { FILES_CACHE, STATIC_PATHS } from '../../initializers/constants'
+import { FILES_CACHE } from '../../initializers/constants'
import { VideoModel } from '../../models/video/video'
import { AbstractVideoStaticFileCache } from './abstract-video-static-file-cache'
import { doRequestAndSaveToFile } from '@server/helpers/requests'
-import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
class VideosPreviewCache extends AbstractVideoStaticFileCache <string> {
function buildGlobalHeaders (body: any) {
return {
- 'Digest': buildDigest(body)
+ Digest: buildDigest(body)
}
}
import { getVideoFilePath } from '@server/lib/video-paths'
export type VideoFileImportPayload = {
- videoUUID: string,
+ videoUUID: string
filePath: string
}
isNewVideo: true
}
- await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
+ await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: dataInput })
}
} catch (err) {
import { federateVideoIfNeeded } from '../../activitypub'
import { retryTransactionWrapper } from '../../../helpers/database-utils'
import { sequelizeTypescript } from '../../../initializers'
-import * as Bluebird from 'bluebird'
import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils'
import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding'
import { Notifier } from '../../notifier'
type: 'optimize'
}
-export type VideoTranscodingPayload = HLSTranscodingPayload | NewResolutionTranscodingPayload
- | OptimizeTranscodingPayload | MergeAudioTranscodingPayload
+export type VideoTranscodingPayload =
+ HLSTranscodingPayload
+ | NewResolutionTranscodingPayload
+ | OptimizeTranscodingPayload
+ | MergeAudioTranscodingPayload
async function processVideoTranscoding (job: Bull.Job) {
const payload = job.data as VideoTranscodingPayload
const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => {
// Maybe the video changed in database, refresh it
- let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t)
+ const videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid, t)
// Video does not exist anymore
if (!videoDatabase) return undefined
await createHlsJobIfEnabled(hlsPayload)
if (resolutionsEnabled.length !== 0) {
- const tasks: (Bluebird<Bull.Job<any>> | Promise<Bull.Job<any>>)[] = []
-
for (const resolution of resolutionsEnabled) {
let dataInput: VideoTranscodingPayload
}
}
- const p = JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
- tasks.push(p)
+ JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput })
}
- await Promise.all(tasks)
-
logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled })
} else {
// No transcoding to do, it's now published
{ type: 'videos-views', payload: {} } |
{ type: 'video-redundancy', payload: VideoRedundancyPayload }
-const handlers: { [ id in JobType ]: (job: Bull.Job) => Promise<any>} = {
+const handlers: { [id in JobType]: (job: Bull.Job) => Promise<any> } = {
'activitypub-http-broadcast': processActivityPubHttpBroadcast,
'activitypub-http-unicast': processActivityPubHttpUnicast,
'activitypub-http-fetcher': processActivityPubHttpFetcher,
private static instance: JobQueue
- private queues: { [ id in JobType ]?: Bull.Queue } = {}
+ private queues: { [id in JobType]?: Bull.Queue } = {}
private initialized = false
private jobRedisPrefix: string
- private constructor () {}
+ private constructor () {
+ }
- async init () {
+ init () {
// Already initialized
if (this.initialized === true) return
this.initialized = true
}
}
- createJob (obj: CreateJobArgument) {
+ createJob (obj: CreateJobArgument): void {
+ this.createJobWithPromise(obj)
+ .catch(err => logger.error('Cannot create job.', { err, obj }))
+ }
+
+ createJobWithPromise (obj: CreateJobArgument) {
const queue = this.queues[obj.type]
if (queue === undefined) {
logger.error('Unknown queue %s: cannot create job.', obj.type)
- throw Error('Unknown queue, cannot create job')
+ return
}
const jobArgs: Bull.JobOptions = {
}
async listForApi (options: {
- state: JobState,
- start: number,
- count: number,
- asc?: boolean,
+ state: JobState
+ start: number
+ count: number
+ asc?: boolean
jobType: JobType
}): Promise<Bull.Job[]> {
const { state, start, count, asc, jobType } = options
const filteredJobTypes = this.filterJobTypes(jobType)
for (const jobType of filteredJobTypes) {
- const queue = this.queues[ jobType ]
+ const queue = this.queues[jobType]
if (queue === undefined) {
logger.error('Unknown queue %s to list jobs.', jobType)
continue
const filteredJobTypes = this.filterJobTypes(jobType)
for (const type of filteredJobTypes) {
- const queue = this.queues[ type ]
+ const queue = this.queues[type]
if (queue === undefined) {
logger.error('Unknown queue %s to count jobs.', type)
continue
const counts = await queue.getJobCounts()
- total += counts[ state ]
+ total += counts[state]
}
return total
private addRepeatableJobs () {
this.queues['videos-views'].add({}, {
repeat: REPEAT_JOBS['videos-views']
- })
+ }).catch(err => logger.error('Cannot add repeatable job.', { err }))
}
private filterJobTypes (jobType?: JobType) {
// Can be filtered by plugins
function isLocalVideoAccepted (object: {
- videoBody: VideoCreate,
- videoFile: Express.Multer.File & { duration?: number },
+ videoBody: VideoCreate
+ videoFile: Express.Multer.File & { duration?: number }
user: UserModel
}): AcceptResult {
return { accepted: true }
}
function isLocalVideoThreadAccepted (_object: {
- commentBody: VideoCommentCreate,
- video: VideoModel,
+ commentBody: VideoCommentCreate
+ video: VideoModel
user: UserModel
}): AcceptResult {
return { accepted: true }
}
function isLocalVideoCommentReplyAccepted (_object: {
- commentBody: VideoCommentCreate,
- parentComment: VideoCommentModel,
- video: VideoModel,
+ commentBody: VideoCommentCreate
+ parentComment: VideoCommentModel
+ video: VideoModel
user: UserModel
}): AcceptResult {
return { accepted: true }
}
function isRemoteVideoAccepted (_object: {
- activity: ActivityCreate,
- videoAP: VideoTorrentObject,
+ activity: ActivityCreate
+ videoAP: VideoTorrentObject
byActor: ActorModel
}): AcceptResult {
return { accepted: true }
}
function isRemoteVideoCommentAccepted (_object: {
- activity: ActivityCreate,
- commentAP: VideoCommentObject,
+ activity: ActivityCreate
+ commentAP: VideoCommentObject
byActor: ActorModel
}): AcceptResult {
return { accepted: true }
import { PeerTubeSocket } from './peertube-socket'
import { CONFIG } from '../initializers/config'
import { VideoPrivacy, VideoState } from '../../shared/models/videos'
-import * as Bluebird from 'bluebird'
import { AccountBlocklistModel } from '../models/account/account-blocklist'
import {
MCommentOwnerVideo,
MVideoFullLight
} from '../typings/models/video'
import {
- MUser, MUserAccount,
+ MUser,
+ MUserAccount,
MUserDefault,
MUserNotifSettingAccount,
MUserWithNotificationSetting,
private static instance: Notifier
- private constructor () {}
+ private constructor () {
+ }
notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void {
// Only notify on public and published videos which are not blacklisted
if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return
this.notifySubscribersOfNewVideo(video)
- .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err }))
+ .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err }))
}
notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void {
if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return
this.notifyOwnedVideoHasBeenPublished(video)
- .catch(err => logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })) // tslint:disable-line:max-line-length
+ .catch(err => {
+ logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })
+ })
}
notifyOnNewComment (comment: MCommentOwnerVideo): void {
notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void {
this.notifyModeratorsOfNewVideoAbuse(videoAbuse)
- .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err }))
+ .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err }))
}
notifyOnVideoAutoBlacklist (videoBlacklist: MVideoBlacklistLightVideo): void {
this.notifyModeratorsOfVideoAutoBlacklist(videoBlacklist)
- .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err }))
+ .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', videoBlacklist.Video.url, { err }))
}
notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void {
this.notifyVideoOwnerOfBlacklist(videoBlacklist)
- .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err }))
+ .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err }))
}
notifyOnVideoUnblacklist (video: MVideoFullLight): void {
notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void {
this.notifyOwnerVideoImportIsFinished(videoImport, success)
- .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err }))
+ .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err }))
}
notifyOnNewUserRegistration (user: MUserDefault): void {
notifyOfNewUserFollow (actorFollow: MActorFollowFull): void {
this.notifyUserOfNewActorFollow(actorFollow)
- .catch(err => {
- logger.error(
- 'Cannot notify owner of channel %s of a new follow by %s.',
- actorFollow.ActorFollowing.VideoChannel.getDisplayName(),
- actorFollow.ActorFollower.Account.getDisplayName(),
- { err }
- )
- })
+ .catch(err => {
+ logger.error(
+ 'Cannot notify owner of channel %s of a new follow by %s.',
+ actorFollow.ActorFollowing.VideoChannel.getDisplayName(),
+ actorFollow.ActorFollower.Account.getDisplayName(),
+ { err }
+ )
+ })
}
notifyOfNewInstanceFollow (actorFollow: MActorFollowFull): void {
return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender })
}
- private async notify <T extends MUserWithNotificationSetting> (options: {
- users: T[],
- notificationCreator: (user: T) => Promise<UserNotificationModelForApi>,
- emailSender: (emails: string[]) => Promise<any> | Bluebird<any>,
+ private async notify<T extends MUserWithNotificationSetting> (options: {
+ users: T[]
+ notificationCreator: (user: T) => Promise<UserNotificationModelForApi>
+ emailSender: (emails: string[]) => void
settingGetter: (user: T) => UserNotificationSettingValue
}) {
const emails: string[] = []
}
if (emails.length !== 0) {
- await options.emailSender(emails)
+ options.emailSender(emails)
}
}
logger.debug('Got result from PeerTube index.', { body })
- await addInstanceInformation(body)
+ addInstanceInformation(body)
return body as ResultList<PeerTubePluginIndex>
} catch (err) {
}
}
-async function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) {
+function addInstanceInformation (result: ResultList<PeerTubePluginIndex>) {
for (const d of result.data) {
d.installed = PluginManager.Instance.isRegistered(d.npmName)
d.name = PluginModel.normalizePluginName(d.npmName)
}
type AlterableVideoConstant = 'language' | 'licence' | 'category'
-type VideoConstant = { [ key in number | string ]: string }
+type VideoConstant = { [key in number | string]: string }
type UpdatedVideoConstant = {
- [ name in AlterableVideoConstant ]: {
- [ npmName: string ]: {
- added: { key: number | string, label: string }[],
+ [name in AlterableVideoConstant]: {
+ [npmName: string]: {
+ added: { key: number | string, label: string }[]
deleted: { key: number | string, label: string }[]
}
}
}
type PluginLocalesTranslations = {
- [ locale: string ]: PluginTranslation
+ [locale: string]: PluginTranslation
}
export class PluginManager implements ServerHook {
private static instance: PluginManager
- private registeredPlugins: { [ name: string ]: RegisteredPlugin } = {}
- private settings: { [ name: string ]: RegisterServerSettingOptions[] } = {}
- private hooks: { [ name: string ]: HookInformationValue[] } = {}
+ private registeredPlugins: { [name: string]: RegisteredPlugin } = {}
+ private settings: { [name: string]: RegisterServerSettingOptions[] } = {}
+ private hooks: { [name: string]: HookInformationValue[] } = {}
private translations: PluginLocalesTranslations = {}
- private updatedVideoConstants: UpdatedVideoConstant = {
+ private readonly updatedVideoConstants: UpdatedVideoConstant = {
language: {},
licence: {},
category: {}
// ###################### Hooks ######################
- async runHook <T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> {
+ async runHook<T> (hookName: ServerHookName, result?: T, params?: any): Promise<T> {
if (!this.hooks[hookName]) return Promise.resolve(result)
const hookType = getHookType(hookName)
clientScripts[c.script] = c
}
- this.registeredPlugins[ npmName ] = {
+ this.registeredPlugins[npmName] = {
npmName,
name: plugin.name,
type: plugin.type,
const plugins: RegisteredPlugin[] = []
for (const npmName of Object.keys(this.registeredPlugins)) {
- const plugin = this.registeredPlugins[ npmName ]
+ const plugin = this.registeredPlugins[npmName]
if (plugin.type !== type) continue
plugins.push(plugin)
}
}
- private addConstant <T extends string | number> (parameters: {
- npmName: string,
- type: AlterableVideoConstant,
- obj: VideoConstant,
- key: T,
+ private addConstant<T extends string | number> (parameters: {
+ npmName: string
+ type: AlterableVideoConstant
+ obj: VideoConstant
+ key: T
label: string
}) {
const { npmName, type, obj, key, label } = parameters
return true
}
- private deleteConstant <T extends string | number> (parameters: {
- npmName: string,
- type: AlterableVideoConstant,
- obj: VideoConstant,
+ private deleteConstant<T extends string | number> (parameters: {
+ npmName: string
+ type: AlterableVideoConstant
+ obj: VideoConstant
key: T
}) {
const { npmName, type, obj, key } = parameters
const { result: packageJSONValid, badFields } = isPackageJSONValid(packageJSON, pluginType)
if (!packageJSONValid) {
const formattedFields = badFields.map(f => `"${f}"`)
- .join(', ')
+ .join(', ')
throw new Error(`PackageJSON is invalid (invalid fields: ${formattedFields}).`)
}
import { CONFIG } from '../initializers/config'
type CachedRoute = {
- body: string,
+ body: string
contentType?: string
statusCode?: string
}
private client: RedisClient
private prefix: string
- private constructor () {}
+ private constructor () {
+ }
init () {
// Already initialized
return Object.assign({},
(CONFIG.REDIS.AUTH && CONFIG.REDIS.AUTH != null) ? { password: CONFIG.REDIS.AUTH } : {},
(CONFIG.REDIS.DB) ? { db: CONFIG.REDIS.DB } : {},
- (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT) ?
- { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT } :
- { path: CONFIG.REDIS.SOCKET }
+ (CONFIG.REDIS.HOSTNAME && CONFIG.REDIS.PORT)
+ ? { host: CONFIG.REDIS.HOSTNAME, port: CONFIG.REDIS.PORT }
+ : { path: CONFIG.REDIS.SOCKET }
)
}
return this.prefix
}
- /************* Forgot password *************/
+ /* ************ Forgot password ************ */
async setResetPasswordVerificationString (userId: number) {
const generatedString = await generateRandomString(32)
return this.getValue(this.generateResetPasswordKey(userId))
}
- /************* Email verification *************/
+ /* ************ Email verification ************ */
async setVerifyEmailVerificationString (userId: number) {
const generatedString = await generateRandomString(32)
return this.getValue(this.generateVerifyEmailKey(userId))
}
- /************* Contact form per IP *************/
+ /* ************ Contact form per IP ************ */
async setContactFormIp (ip: string) {
return this.setValue(this.generateContactFormKey(ip), '1', CONTACT_FORM_LIFETIME)
return this.exists(this.generateContactFormKey(ip))
}
- /************* Views per IP *************/
+ /* ************ Views per IP ************ */
setIPVideoView (ip: string, videoUUID: string) {
return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME)
return this.exists(this.generateViewKey(ip, videoUUID))
}
- /************* API cache *************/
+ /* ************ API cache ************ */
async getCachedRoute (req: express.Request) {
const cached = await this.getObject(this.generateCachedRouteKey(req))
}
setCachedRoute (req: express.Request, body: any, lifetime: number, contentType?: string, statusCode?: number) {
- const cached: CachedRoute = Object.assign({}, {
- body: body.toString()
- },
- (contentType) ? { contentType } : null,
- (statusCode) ? { statusCode: statusCode.toString() } : null
+ const cached: CachedRoute = Object.assign(
+ {},
+ { body: body.toString() },
+ (contentType) ? { contentType } : null,
+ (statusCode) ? { statusCode: statusCode.toString() } : null
)
return this.setObject(this.generateCachedRouteKey(req), cached, lifetime)
}
- /************* Video views *************/
+ /* ************ Video views ************ */
addVideoView (videoId: number) {
const keyIncr = this.generateVideoViewKey(videoId)
])
}
- /************* Keys generation *************/
+ /* ************ Keys generation ************ */
generateCachedRouteKey (req: express.Request) {
return req.method + '-' + req.originalUrl
return 'contact-form-' + ip
}
- /************* Redis helpers *************/
+ /* ************ Redis helpers ************ */
private getValue (key: string) {
return new Promise<string>((res, rej) => {
})
}
- private setObject (key: string, obj: { [ id: string ]: string }, expirationMilliseconds: number) {
+ private setObject (key: string, obj: { [id: string]: string }, expirationMilliseconds: number) {
return new Promise<void>((res, rej) => {
this.client.hmset(this.prefix + key, obj, (err, ok) => {
if (err) return rej(err)
}
private getObject (key: string) {
- return new Promise<{ [ id: string ]: string }>((res, rej) => {
+ return new Promise<{ [id: string]: string }>((res, rej) => {
this.client.hgetall(this.prefix + key, (err, value) => {
if (err) return rej(err)
isAutoFollow: true
}
- await JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
- .catch(err => logger.error('Cannot create follow job for %s.', unfollowedHost, err))
+ JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
}
}
const results = await getLatestPluginsVersion(npmNames)
for (const result of results) {
- const plugin = pluginIndex[ result.npmName ]
+ const plugin = pluginIndex[result.npmName]
if (!result.latestVersion) continue
if (
import { logger } from '../../helpers/logger'
import { AbstractScheduler } from './abstract-scheduler'
import { SCHEDULER_INTERVALS_MS } from '../../initializers/constants'
-import { UserVideoHistoryModel } from '../../models/account/user-video-history'
import { CONFIG } from '../../initializers/config'
-import { isTestInstance } from '../../helpers/core-utils'
import { VideoViewModel } from '../../models/video/video-views'
export class RemoveOldViewsScheduler extends AbstractScheduler {
import { VideoModel } from '@server/models/video/video'
type CandidateToDuplicate = {
- redundancy: VideosRedundancyStrategy,
- video: MVideoWithAllFiles,
- files: MVideoFile[],
+ redundancy: VideosRedundancyStrategy
+ video: MVideoWithAllFiles
+ files: MVideoFile[]
streamingPlaylists: MStreamingPlaylistFiles[]
}
function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) {
const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size)
- const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel()
+ const thumbnail = existingThumbnail || new ThumbnailModel()
thumbnail.filename = filename
thumbnail.height = height
}
async function createThumbnailFromFunction (parameters: {
- thumbnailCreator: () => Promise<any>,
- filename: string,
- height: number,
- width: number,
- type: ThumbnailType,
- automaticallyGenerated?: boolean,
- fileUrl?: string,
+ thumbnailCreator: () => Promise<any>
+ filename: string
+ height: number
+ width: number
+ type: ThumbnailType
+ automaticallyGenerated?: boolean
+ fileUrl?: string
existingThumbnail?: MThumbnail
}) {
const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters
- const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel()
+ const thumbnail = existingThumbnail || new ThumbnailModel()
thumbnail.filename = filename
thumbnail.height = height
type ChannelNames = { name: string, displayName: string }
async function createUserAccountAndChannelAndPlaylist (parameters: {
- userToCreate: MUser,
- userDisplayName?: string,
- channelNames?: ChannelNames,
+ userToCreate: MUser
+ userDisplayName?: string
+ channelNames?: ChannelNames
validateUser?: boolean
}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> {
const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters
}
async function createLocalAccountWithoutKeys (parameters: {
- name: string,
- displayName?: string,
- userId: number | null,
- applicationId: number | null,
- t: Transaction | undefined,
+ name: string
+ displayName?: string
+ userId: number | null
+ applicationId: number | null
+ t: Transaction | undefined
type?: ActivityPubActorType
}) {
const { name, displayName, userId, applicationId, t, type = 'Person' } = parameters
import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models'
async function autoBlacklistVideoIfNeeded (parameters: {
- video: MVideoWithBlacklistLight,
- user?: MUser,
- isRemote: boolean,
- isNew: boolean,
- notify?: boolean,
+ video: MVideoWithBlacklistLight
+ user?: MUser
+ isRemote: boolean
+ isNew: boolean
+ notify?: boolean
transaction?: Transaction
}) {
const { video, user, isRemote, isNew, notify = true, transaction } = parameters
- const doAutoBlacklist = await Hooks.wrapPromiseFun(
+ const doAutoBlacklist = await Hooks.wrapFun(
autoBlacklistNeeded,
{ video, user, isRemote, isNew },
'filter:video.auto-blacklist.result'
return true
}
-async function autoBlacklistNeeded (parameters: {
- video: MVideoWithBlacklistLight,
- isRemote: boolean,
- isNew: boolean,
+function autoBlacklistNeeded (parameters: {
+ video: MVideoWithBlacklistLight
+ isRemote: boolean
+ isNew: boolean
user?: MUser
}) {
const { user, video, isRemote, isNew } = parameters
import { VideoModel } from '../models/video/video'
import { MAccountId, MChannelDefault, MChannelId } from '../typings/models'
-type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault &
- { Account?: T }
+type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault & { Account?: T }
async function createLocalVideoChannel <T extends MAccountId> (
videoChannelInfo: VideoChannelCreate,
import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models'
async function createVideoComment (obj: {
- text: string,
- inReplyToComment: MComment | null,
- video: MVideoFullLight,
+ text: string
+ inReplyToComment: MComment | null
+ video: MVideoFullLight
account: MAccountDefault
}, t: Sequelize.Transaction) {
let originCommentId: number | null = null
import { getOrCreateActorAndServerAndModel } from '../lib/activitypub'
import { loadActorUrlOrGetFromWebfinger } from '../helpers/webfinger'
import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor'
+import { getAPId } from '@server/helpers/activitypub'
async function checkSignature (req: Request, res: Response, next: NextFunction) {
try {
// Forwarded activity
const bodyActor = req.body.actor
- const bodyActorId = bodyActor && bodyActor.id ? bodyActor.id : bodyActor
+ const bodyActorId = getAPId(bodyActor)
if (bodyActorId && bodyActorId !== actor.url) {
const jsonLDSignatureChecked = await checkJsonLDSignature(req, res)
if (jsonLDSignatureChecked !== true) return
const baseDirectives = Object.assign({},
{
- defaultSrc: ["'none'"], // by default, not specifying default-src = '*'
- connectSrc: ['*', 'data:'],
- mediaSrc: ["'self'", 'https:', 'blob:'],
- fontSrc: ["'self'", 'data:'],
- imgSrc: ["'self'", 'data:', 'blob:'],
- scriptSrc: ["'self' 'unsafe-inline' 'unsafe-eval'", 'blob:'],
- styleSrc: ["'self' 'unsafe-inline'"],
- objectSrc: ["'none'"], // only define to allow plugins, else let defaultSrc 'none' block it
- formAction: ["'self'"],
- frameAncestors: ["'none'"],
- baseUri: ["'self'"],
- manifestSrc: ["'self'"],
- frameSrc: ["'self'"], // instead of deprecated child-src / self because of test-embed
- workerSrc: ["'self'", 'blob:'] // instead of deprecated child-src
+ defaultSrc: [ '\'none\'' ], // by default, not specifying default-src = '*'
+ connectSrc: [ '*', 'data:' ],
+ mediaSrc: [ '\'self\'', 'https:', 'blob:' ],
+ fontSrc: [ '\'self\'', 'data:' ],
+ imgSrc: [ '\'self\'', 'data:', 'blob:' ],
+ scriptSrc: [ '\'self\' \'unsafe-inline\' \'unsafe-eval\'', 'blob:' ],
+ styleSrc: [ '\'self\' \'unsafe-inline\'' ],
+ objectSrc: [ '\'none\'' ], // only define to allow plugins, else let defaultSrc 'none' block it
+ formAction: [ '\'self\'' ],
+ frameAncestors: [ '\'none\'' ],
+ baseUri: [ '\'self\'' ],
+ manifestSrc: [ '\'self\'' ],
+ frameSrc: [ '\'self\'' ], // instead of deprecated child-src / self because of test-embed
+ workerSrc: [ '\'self\'', 'blob:' ] // instead of deprecated child-src
},
CONFIG.CSP.REPORT_URI ? { reportUri: CONFIG.CSP.REPORT_URI } : {},
CONFIG.WEBSERVER.SCHEME === 'https' ? { upgradeInsecureRequests: true } : {}
})
const embedCSP = helmet.contentSecurityPolicy({
- directives: Object.assign({}, baseDirectives, { frameAncestors: ['*'] }),
+ directives: Object.assign({}, baseDirectives, { frameAncestors: [ '*' ] }),
browserSniff: false, // assumes a modern browser, but allows CDN in front
reportOnly: CONFIG.CSP.REPORT_ONLY
})
-import * as ipaddr from 'ipaddr.js'
-import { format } from 'util'
-
const advertiseDoNotTrack = (_, res, next) => {
res.setHeader('Tk', 'N')
return next()
return next()
})
+ .catch(err => logger.error('Cannot get access token.', { err }))
}
function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) {
const setDefaultSearchSort = setDefaultSortFactory('-match')
function setBlacklistSort (req: express.Request, res: express.Response, next: express.NextFunction) {
- let newSort: SortType = { sortModel: undefined, sortValue: '' }
+ const newSort: SortType = { sortModel: undefined, sortValue: '' }
if (!req.query.sort) req.query.sort = '-createdAt'
const updateAvatarValidator = [
body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage(
- 'This file is not supported or too large. Please, make sure it is of the following type : '
- + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
+ 'This file is not supported or too large. Please, make sure it is of the following type : ' +
+ CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
),
(req: express.Request, res: express.Response, next: express.NextFunction) => {
body('theme.default').custom(v => isThemeNameValid(v) && isThemeRegistered(v)).withMessage('Should have a valid theme'),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking customConfigUpdateValidator parameters', { parameters: req.body })
if (areValidationErrors(req, res)) return
let acceptableContentTypes: string[]
if (format === 'atom' || format === 'atom1') {
- acceptableContentTypes = ['application/atom+xml', 'application/xml', 'text/xml']
+ acceptableContentTypes = [ 'application/atom+xml', 'application/xml', 'text/xml' ]
} else if (format === 'json' || format === 'json1') {
- acceptableContentTypes = ['application/json']
+ acceptableContentTypes = [ 'application/json' ]
} else if (format === 'rss' || format === 'rss2') {
- acceptableContentTypes = ['application/rss+xml', 'application/xml', 'text/xml']
+ acceptableContentTypes = [ 'application/rss+xml', 'application/xml', 'text/xml' ]
} else {
- acceptableContentTypes = ['application/xml', 'text/xml']
+ acceptableContentTypes = [ 'application/xml', 'text/xml' ]
}
if (req.accepts(acceptableContentTypes)) {
query('target')
.custom(isVideoRedundancyTarget).withMessage('Should have a valid video redundancies target'),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking listVideoRedundanciesValidator parameters', { parameters: req.query })
if (areValidationErrors(req, res)) return
import { UserRole } from '../../../shared/models/users'
import { MUserDefault } from '@server/typings/models'
import { Hooks } from '@server/lib/plugins/hooks'
-import { isLocalVideoAccepted } from '@server/lib/moderation'
const usersAddValidator = [
body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
]
const deleteMeValidator = [
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
const user = res.locals.oauth.token.User
if (user.username === 'root') {
return res.status(400)
]
const ensureUserRegistrationAllowedForIP = [
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
const allowed = isSignupAllowedForCurrentIP(req.ip)
if (allowed === false) {
]
const ensureAuthUserOwnsAccountValidator = [
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
const user = res.locals.oauth.token.User
if (res.locals.account.id !== user.Account.id) {
param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
param('captionLanguage').custom(isVideoCaptionLanguageValid).not().isEmpty().withMessage('Should have a valid caption language'),
body('captionfile')
- .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile')).withMessage(
- `This caption file is not supported or too large. Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: `
- + Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ')
- ),
+ .custom((_, { req }) => isVideoCaptionFile(req.files, 'captionfile'))
+ .withMessage(
+ 'This caption file is not supported or too large. ' +
+ `Please, make sure it is under ${CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE} and one of the following mimetypes: ` +
+ Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT).map(key => `${key} (${MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT[key]})`).join(', ')
+ ),
async (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking addVideoCaption parameters', { parameters: req.body })
if (areValidationErrors(req, res)) return
if (!await doesVideoExist(req.params.videoId, res)) return
if (!isVideoCommentsEnabled(res.locals.videoAll, res)) return
- if (!await isVideoCommentAccepted(req, res, res.locals.videoAll,false)) return
+ if (!await isVideoCommentAccepted(req, res, res.locals.videoAll, false)) return
return next()
}
.optional()
.custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'),
body('torrentfile')
- .custom((value, { req }) => isVideoImportTorrentFile(req.files)).withMessage(
- 'This torrent file is not supported or too large. Please, make sure it is of the following type: '
- + CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ')
- ),
+ .custom((value, { req }) => isVideoImportTorrentFile(req.files))
+ .withMessage(
+ 'This torrent file is not supported or too large. Please, make sure it is of the following type: ' +
+ CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ')
+ ),
body('name')
.optional()
.custom(isVideoNameValid).withMessage('Should have a valid name'),
function getCommonPlaylistEditAttributes () {
return [
body('thumbnailfile')
- .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
- 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: '
- + CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
- ),
+ .custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile'))
+ .withMessage(
+ 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
+ CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.IMAGE.EXTNAME.join(', ')
+ ),
body('description')
.optional()
const videoRatingValidator = [
query('rating').optional().custom(isRatingValid).withMessage('Value must be one of "like" or "dislike"'),
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
+ (req: express.Request, res: express.Response, next: express.NextFunction) => {
logger.debug('Checking rating parameter', { parameters: req.params })
if (areValidationErrors(req, res)) return
const videosAddValidator = getCommonVideoEditAttributes().concat([
body('videofile')
.custom((value, { req }) => isVideoFile(req.files)).withMessage(
- 'This file is not supported or too large. Please, make sure it is of the following type: '
- + CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
+ 'This file is not supported or too large. Please, make sure it is of the following type: ' +
+ CONSTRAINTS_FIELDS.VIDEOS.EXTNAME.join(', ')
),
body('name').custom(isVideoNameValid).withMessage('Should have a valid name'),
body('channelId')
// Check if the user who did the request is able to change the ownership of the video
if (!checkUserCanTerminateOwnershipChange(res.locals.oauth.token.User, res.locals.videoChangeOwnership, res)) return
- return next()
- },
- async (req: express.Request, res: express.Response, next: express.NextFunction) => {
const videoChangeOwnership = res.locals.videoChangeOwnership
- if (videoChangeOwnership.status === VideoChangeOwnershipStatus.WAITING) {
- return next()
- } else {
+ if (videoChangeOwnership.status !== VideoChangeOwnershipStatus.WAITING) {
res.status(403)
- .json({ error: 'Ownership already accepted or refused' })
-
+ .json({ error: 'Ownership already accepted or refused' })
return
}
+
+ return next()
}
]
return [
body('thumbnailfile')
.custom((value, { req }) => isVideoImage(req.files, 'thumbnailfile')).withMessage(
- 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: '
- + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
- ),
+ 'This thumbnail file is not supported or too large. Please, make sure it is of the following type: ' +
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
+ ),
body('previewfile')
.custom((value, { req }) => isVideoImage(req.files, 'previewfile')).withMessage(
- 'This preview file is not supported or too large. Please, make sure it is of the following type: '
- + CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
- ),
+ 'This preview file is not supported or too large. Please, make sure it is of the following type: ' +
+ CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME.join(', ')
+ ),
body('category')
.optional()
static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> {
const options: FindOptions = {
where: {
- [ Op.or]: [
+ [Op.or]: [
{
accountId,
videoId
}
static listByAccountForApi (options: {
- start: number,
- count: number,
- sort: string,
- type?: string,
+ start: number
+ count: number
+ sort: string
+ type?: string
accountId: number
}) {
const query: FindOptions = {
required: true,
include: [
{
- model: VideoChannelModel.scope({ method: [VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),
+ model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, { withAccount: true } as SummaryOptions ] }),
required: true
}
]
]
}))
@Scopes(() => ({
- [ ScopeNames.SUMMARY ]: (options: SummaryOptions = {}) => {
+ [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => {
const whereActor = options.whereActor || undefined
const serverInclude: IncludeOptions = {
const query = {
where: {
- [ Op.or ]: [
+ [Op.or]: [
{
userId: {
- [ Op.ne ]: null
+ [Op.ne]: null
}
},
{
applicationId: {
- [ Op.ne ]: null
+ [Op.ne]: null
}
}
]
toFormattedJSON (this: UserNotificationModelForApi): UserNotification {
const video = this.Video
- ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) })
+ ? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) })
: undefined
const videoImport = this.VideoImport ? {
-import { FindOptions, literal, Op, QueryTypes, where, fn, col } from 'sequelize'
+import { FindOptions, literal, Op, QueryTypes, where, fn, col, WhereOptions } from 'sequelize'
import {
AfterDestroy,
AfterUpdate,
required: true,
where: {
type: {
- [ Op.ne ]: VideoPlaylistType.REGULAR
+ [Op.ne]: VideoPlaylistType.REGULAR
}
}
}
@AllowNull(false)
@Default(true)
- @Is('UserAutoPlayNextVideoPlaylist', value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean'))
+ @Is(
+ 'UserAutoPlayNextVideoPlaylist',
+ value => throwIfNotValid(value, isUserAutoPlayNextVideoPlaylistValid, 'auto play next video for playlists boolean')
+ )
@Column
autoPlayNextVideoPlaylist: boolean
}
static listForApi (start: number, count: number, sort: string, search?: string) {
- let where = undefined
+ let where: WhereOptions
+
if (search) {
where = {
[Op.or]: [
},
{
username: {
- [ Op.iLike ]: '%' + search + '%'
+ [Op.iLike]: '%' + search + '%'
}
}
]
[
literal(
'(' +
- 'SELECT COALESCE(SUM("size"), 0) ' +
- 'FROM (' +
- 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
- 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
- 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
- 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
- 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' +
- ') t' +
+ 'SELECT COALESCE(SUM("size"), 0) ' +
+ 'FROM (' +
+ 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
+ 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
+ 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
+ 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
+ 'WHERE "account"."userId" = "UserModel"."id" GROUP BY "video"."id"' +
+ ') t' +
')'
),
'videoQuotaUsed'
}
return UserModel.findAndCountAll(query)
- .then(({ rows, count }) => {
- return {
- data: rows,
- total: count
- }
- })
+ .then(({ rows, count }) => {
+ return {
+ data: rows,
+ total: count
+ }
+ })
}
static listWithRight (right: UserRight): Bluebird<MUserDefault[]> {
const roles = Object.keys(USER_ROLE_LABELS)
- .map(k => parseInt(k, 10) as UserRole)
- .filter(role => hasUserRight(role, right))
+ .map(k => parseInt(k, 10) as UserRole)
+ .filter(role => hasUserRight(role, right))
const query = {
where: {
required: true,
include: [
{
- attributes: [ ],
+ attributes: [],
model: ActorModel.unscoped(),
required: true,
where: {
},
include: [
{
- attributes: [ ],
+ attributes: [],
as: 'ActorFollowings',
model: ActorFollowModel.unscoped(),
required: true,
static loadByUsername (username: string): Bluebird<MUserDefault> {
const query = {
where: {
- username: { [ Op.iLike ]: username }
+ username: { [Op.iLike]: username }
}
}
static loadForMeAPI (username: string): Bluebird<MUserNotifSettingChannelDefault> {
const query = {
where: {
- username: { [ Op.iLike ]: username }
+ username: { [Op.iLike]: username }
}
}
const query = {
where: {
- [ Op.or ]: [
+ [Op.or]: [
where(fn('lower', col('username')), fn('lower', username)),
{ email }
const query = {
where: {
username: {
- [ Op.like ]: `%${search}%`
+ [Op.like]: `%${search}%`
}
},
limit: 10
videoLanguages: this.videoLanguages,
role: this.role,
- roleLabel: USER_ROLE_LABELS[ this.role ],
+ roleLabel: USER_ROLE_LABELS[this.role],
videoQuota: this.videoQuota,
videoQuotaDaily: this.videoQuotaDaily,
if (Array.isArray(this.Account.VideoChannels) === true) {
json.videoChannels = this.Account.VideoChannels
- .map(c => c.toFormattedJSON())
- .sort((v1, v2) => {
- if (v1.createdAt < v2.createdAt) return -1
- if (v1.createdAt === v2.createdAt) return 0
+ .map(c => c.toFormattedJSON())
+ .sort((v1, v2) => {
+ if (v1.createdAt < v2.createdAt) return -1
+ if (v1.createdAt === v2.createdAt) return 0
- return 1
- })
+ return 1
+ })
}
return json
const formatted = this.toFormattedJSON()
const specialPlaylists = this.Account.VideoPlaylists
- .map(p => ({ id: p.id, name: p.name, type: p.type }))
+ .map(p => ({ id: p.id, name: p.name, type: p.type }))
return Object.assign(formatted, { specialPlaylists })
}
return 'SELECT SUM("size") AS "total" ' +
'FROM (' +
- 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
- 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
- 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
- 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
- 'WHERE "account"."userId" = $userId ' + andWhere +
- 'GROUP BY "video"."id"' +
+ 'SELECT MAX("videoFile"."size") AS "size" FROM "videoFile" ' +
+ 'INNER JOIN "video" ON "videoFile"."videoId" = "video"."id" ' +
+ 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
+ 'INNER JOIN "account" ON "videoChannel"."accountId" = "account"."id" ' +
+ 'WHERE "account"."userId" = $userId ' + andWhere +
+ 'GROUP BY "video"."id"' +
') t'
}
import * as Bluebird from 'bluebird'
-import { values, difference } from 'lodash'
+import { difference, values } from 'lodash'
import {
AfterCreate,
AfterDestroy,
import { getServerActor } from '../../helpers/utils'
import { ACTOR_FOLLOW_SCORE, FOLLOW_STATES, SERVER_ACTOR_NAME } from '../../initializers/constants'
import { ServerModel } from '../server/server'
-import { createSafeIn, getSort, getFollowsSort } from '../utils'
+import { createSafeIn, getFollowsSort, getSort } from '../utils'
import { ActorModel, unusedActorAttributesForAPI } from './actor'
import { VideoChannelModel } from '../video/video-channel'
import { AccountModel } from '../account/account'
MActorFollowSubscriptions
} from '@server/typings/models'
import { ActivityPubActorType } from '@shared/models'
-import { afterCommitIfTransaction } from '@server/helpers/database-utils'
@Table({
tableName: 'actorFollow',
return ActorFollowModel.findOne(query)
.then(result => {
- if (result && result.ActorFollowing.VideoChannel) {
+ if (result?.ActorFollowing.VideoChannel) {
result.ActorFollowing.VideoChannel.Actor = result.ActorFollowing
}
.map(t => {
if (t.host) {
return {
- [ Op.and ]: [
+ [Op.and]: [
{
- '$preferredUsername$': t.name
+ $preferredUsername$: t.name
},
{
- '$host$': t.host
+ $host$: t.host
}
]
}
}
return {
- [ Op.and ]: [
+ [Op.and]: [
{
- '$preferredUsername$': t.name
+ $preferredUsername$: t.name
},
{
- '$serverId$': null
+ $serverId$: null
}
]
}
const query = {
attributes: [],
where: {
- [ Op.and ]: [
+ [Op.and]: [
{
- [ Op.or ]: whereTab
+ [Op.or]: whereTab
},
{
actorId
}
static listFollowingForApi (options: {
- id: number,
- start: number,
- count: number,
- sort: string,
- state?: FollowState,
- actorType?: ActivityPubActorType,
+ id: number
+ start: number
+ count: number
+ sort: string
+ state?: FollowState
+ actorType?: ActivityPubActorType
search?: string
}) {
const { id, start, count, sort, search, state, actorType } = options
if (search) {
Object.assign(followingServerWhere, {
host: {
- [ Op.iLike ]: '%' + search + '%'
+ [Op.iLike]: '%' + search + '%'
}
})
}
}
static listFollowersForApi (options: {
- actorId: number,
- start: number,
- count: number,
- sort: string,
- state?: FollowState,
- actorType?: ActivityPubActorType,
+ actorId: number
+ start: number
+ count: number
+ sort: string
+ state?: FollowState
+ actorType?: ActivityPubActorType
search?: string
}) {
const { actorId, start, count, sort, search, state, actorType } = options
if (search) {
Object.assign(followerServerWhere, {
host: {
- [ Op.iLike ]: '%' + search + '%'
+ [Op.iLike]: '%' + search + '%'
}
})
}
const tasks: Bluebird<any>[] = []
- for (let selection of selections) {
+ for (const selection of selections) {
let query = 'SELECT ' + selection + ' FROM "actor" ' +
'INNER JOIN "actorFollow" ON "actorFollow"."' + firstJoin + '" = "actor"."id" ' +
'INNER JOIN "actor" AS "Follows" ON "actorFollow"."' + secondJoin + '" = "Follows"."id" ' +
Table,
UpdatedAt
} from 'sequelize-typescript'
-import { ActivityPubActorType } from '../../../shared/models/activitypub'
+import { ActivityIconObject, ActivityPubActorType } from '../../../shared/models/activitypub'
import { Avatar } from '../../../shared/models/avatars/avatar.model'
import { activityPubContextify } from '../../helpers/activitypub'
import {
const query = {
where: {
followersUrl: {
- [ Op.in ]: followersUrls
+ [Op.in]: followersUrls
}
},
transaction
.findOne(query)
.then(actor => {
if (preferredUsername === SERVER_ACTOR_NAME) {
- ActorModel.localNameCache[ preferredUsername ] = actor
+ ActorModel.localNameCache[preferredUsername] = actor
}
return actor
.findOne(query)
.then(actor => {
if (preferredUsername === SERVER_ACTOR_NAME) {
- ActorModel.localUrlCache[ preferredUsername ] = actor
+ ActorModel.localUrlCache[preferredUsername] = actor
}
return actor
}
toActivityPubObject (this: MActorAP, name: string) {
- let icon = undefined
+ let icon: ActivityIconObject
+
if (this.avatarId) {
const extension = extname(this.Avatar.filename)
+
icon = {
type: 'Image',
mediaType: extension === '.png' ? 'image/png' : 'image/jpeg',
export type OAuthTokenInfo = {
refreshToken: string
- refreshTokenExpiresAt: Date,
+ refreshTokenExpiresAt: Date
client: {
id: number
- },
+ }
user: {
id: number
}
}
@Scopes(() => ({
- [ ScopeNames.WITH_VIDEO ]: {
+ [ScopeNames.WITH_VIDEO]: {
include: [
{
model: VideoFileModel,
logger.info('Removing duplicated video streaming playlist %s.', videoUUID)
videoStreamingPlaylist.Video.removeStreamingPlaylistFiles(videoStreamingPlaylist, true)
- .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err }))
+ .catch(err => logger.error('Cannot delete video streaming playlist files of %s.', videoUUID, { err }))
}
return undefined
},
include: [
{
- attributes: [ ],
+ attributes: [],
model: VideoFileModel,
required: true,
include: [
{
- attributes: [ ],
+ attributes: [],
model: VideoModel,
required: true,
where: {
}
return VideoRedundancyModel.findOne(query)
- .then(r => !!r)
+ .then(r => !!r)
}
static async getVideoSample (p: Bluebird<VideoModel[]>) {
where: {
privacy: VideoPrivacy.PUBLIC,
views: {
- [ Op.gte ]: minViews
+ [Op.gte]: minViews
}
},
include: [
actorId: actor.id,
strategy,
createdAt: {
- [ Op.lt ]: expiredDate
+ [Op.lt]: expiredDate
}
}
}
where: {
actorId: actor.id,
expiresOn: {
- [ Op.lt ]: new Date()
+ [Op.lt]: new Date()
}
}
}
[Op.ne]: actor.id
},
expiresOn: {
- [ Op.lt ]: new Date(),
- [ Op.ne ]: null
+ [Op.lt]: new Date(),
+ [Op.ne]: null
}
}
}
}
static listForApi (options: {
- start: number,
- count: number,
- sort: string,
- target: VideoRedundanciesTarget,
+ start: number
+ count: number
+ sort: string
+ target: VideoRedundanciesTarget
strategy?: string
}) {
const { start, count, sort, target, strategy } = options
- let redundancyWhere: WhereOptions = {}
- let videosWhere: WhereOptions = {}
+ const redundancyWhere: WhereOptions = {}
+ const videosWhere: WhereOptions = {}
let redundancySqlSuffix = ''
if (target === 'my-videos') {
const videoFilterWhere = {
[Op.and]: [
{
- [ Op.or ]: [
+ [Op.or]: [
{
id: {
- [ Op.in ]: literal(
+ [Op.in]: literal(
'(' +
'SELECT "videoId" FROM "videoFile" ' +
'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoFileId" = "videoFile".id' +
},
{
id: {
- [ Op.in ]: literal(
+ [Op.in]: literal(
'(' +
'select "videoId" FROM "videoStreamingPlaylist" ' +
'INNER JOIN "videoRedundancy" ON "videoRedundancy"."videoStreamingPlaylistId" = "videoStreamingPlaylist".id' +
}
return VideoRedundancyModel.findOne(query)
- .then((r: any) => ({
- totalUsed: parseAggregateResult(r.totalUsed),
- totalVideos: r.totalVideos,
- totalVideoFiles: r.totalVideoFiles
- }))
+ .then((r: any) => ({
+ totalUsed: parseAggregateResult(r.totalUsed),
+ totalVideos: r.totalVideos,
+ totalVideoFiles: r.totalVideoFiles
+ }))
}
static toFormattedJSONStatic (video: MVideoForRedundancyAPI): VideoRedundancy {
- let filesRedundancies: FileRedundancyInformation[] = []
- let streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = []
+ const filesRedundancies: FileRedundancyInformation[] = []
+ const streamingPlaylistsRedundancies: StreamingPlaylistRedundancyInformation[] = []
for (const file of video.VideoFiles) {
for (const redundancy of file.RedundancyVideos) {
expires: this.expiresOn ? this.expiresOn.toISOString() : null,
url: {
type: 'Link',
- mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ this.VideoFile.extname ] as any,
+ mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[this.VideoFile.extname] as any,
href: this.fileUrl,
height: this.VideoFile.resolution,
size: this.VideoFile.size,
const notIn = literal(
'(' +
- `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` +
+ `SELECT "videoFileId" FROM "videoRedundancy" WHERE "actorId" = ${actor.id} AND "videoFileId" IS NOT NULL` +
')'
)
required: true,
where: {
id: {
- [ Op.notIn ]: notIn
+ [Op.notIn]: notIn
}
}
}
}
static listForApi (options: {
- pluginType?: PluginType,
- uninstalled?: boolean,
- start: number,
- count: number,
+ pluginType?: PluginType
+ uninstalled?: boolean
+ start: number
+ count: number
sort: string
}) {
const { uninstalled = false } = options
function getBlacklistSort (model: any, value: string, lastSort: OrderItem = [ 'id', 'ASC' ]): OrderItem[] {
const [ firstSort ] = getSort(value)
- if (model) return [ [ literal(`"${model}.${firstSort[ 0 ]}" ${firstSort[ 1 ]}`) ], lastSort ] as any[] // FIXME: typings
+ if (model) return [ [ literal(`"${model}.${firstSort[0]}" ${firstSort[1]}`) ], lastSort ] as any[] // FIXME: typings
return [ firstSort, lastSort ]
}
'SELECT "actor"."serverId" FROM "actorFollow" ' +
'INNER JOIN "actor" ON actor.id = "actorFollow"."targetActorId" ' +
'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
- ')'
+ ')'
}
function buildWhereIdOrUUID (id: number | string) {
@UpdatedAt
updatedAt: Date
- private static types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = {
+ private static readonly types: { [ id in ThumbnailType ]: { label: string, directory: string, staticPath: string } } = {
[ThumbnailType.MINIATURE]: {
label: 'miniature',
directory: CONFIG.STORAGE.THUMBNAILS_DIR,
}
static listForApi (parameters: {
- start: number,
- count: number,
- sort: string,
+ start: number
+ count: number
+ sort: string
serverAccountId: number
user?: MUserAccountId
}) {
BeforeDestroy,
BelongsTo,
Column,
- CreatedAt, DataType,
+ CreatedAt,
+ DataType,
ForeignKey,
Is,
Model,
import { VideoModel } from './video'
import { isVideoCaptionLanguageValid } from '../../helpers/custom-validators/video-captions'
import { VideoCaption } from '../../../shared/models/videos/caption/video-caption.model'
-import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants'
+import { CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, VIDEO_LANGUAGES, WEBSERVER } from '../../initializers/constants'
import { join } from 'path'
import { logger } from '../../helpers/logger'
import { remove } from 'fs-extra'
import { CONFIG } from '../../initializers/config'
import * as Bluebird from 'bluebird'
-import { MVideo, MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models'
+import { MVideoAccountLight, MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models'
import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub'
export enum ScopeNames {
import { VideoModel } from './video'
import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
import { ServerModel } from '../server/server'
-import { FindOptions, ModelIndexesOptions, Op } from 'sequelize'
+import { FindOptions, Op } from 'sequelize'
import { AvatarModel } from '../avatar/avatar'
import { VideoPlaylistModel } from './video-playlist'
import * as Bluebird from 'bluebird'
},
{
serverId: {
- [ Op.in ]: Sequelize.literal(inQueryInstanceFollow)
+ [Op.in]: Sequelize.literal(inQueryInstanceFollow)
}
}
]
}
static listByAccount (options: {
- accountId: number,
- start: number,
- count: number,
+ accountId: number
+ start: number
+ count: number
sort: string
}) {
const query = {
}
static async listThreadsForApi (parameters: {
- videoId: number,
- start: number,
- count: number,
- sort: string,
+ videoId: number
+ start: number
+ count: number
+ sort: string
user?: MUserAccountId
}) {
const { videoId, start, count, sort, user } = parameters
}
static async listThreadCommentsForApi (parameters: {
- videoId: number,
- threadId: number,
+ videoId: number
+ threadId: number
user?: MUserAccountId
}) {
const { videoId, threadId, user } = parameters
order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order,
where: {
videoId,
- [ Op.or ]: [
+ [Op.or]: [
{ id: threadId },
{ originCommentId: threadId }
],
order: [ [ 'createdAt', order ] ] as Order,
where: {
id: {
- [ Op.in ]: Sequelize.literal('(' +
+ [Op.in]: Sequelize.literal('(' +
'WITH RECURSIVE children (id, "inReplyToCommentId") AS ( ' +
`SELECT id, "inReplyToCommentId" FROM "videoComment" WHERE id = ${comment.id} ` +
'UNION ' +
') ' +
'SELECT id FROM children' +
')'),
- [ Op.ne ]: comment.id
+ [Op.ne]: comment.id
}
},
transaction: t
}
isDeleted () {
- return null !== this.deletedAt
+ return this.deletedAt !== null
}
extractMentions () {
export type VideoFormattingJSONOptions = {
completeDescription?: boolean
additionalAttributes: {
- state?: boolean,
- waitTranscoding?: boolean,
- scheduledUpdate?: boolean,
+ state?: boolean
+ waitTranscoding?: boolean
+ scheduledUpdate?: boolean
blacklistInfo?: boolean
}
}
+
function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video {
const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined
): VideoFile[] {
return videoFiles
.map(videoFile => {
- let resolutionLabel = videoFile.resolution + 'p'
-
return {
resolution: {
id: videoFile.resolution,
- label: resolutionLabel
+ label: videoFile.resolution + 'p'
},
magnetUri: generateMagnetUri(model, videoFile, baseUrlHttp, baseUrlWs),
size: videoFile.size,
for (const file of files) {
acc.push({
type: 'Link',
- mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[ file.extname ] as any,
+ mediaType: MIMETYPES.VIDEO.EXT_MIMETYPE[file.extname] as any,
href: model.getVideoFileUrl(file, baseUrlHttp),
height: file.resolution,
size: file.size,
addVideoFilesInAPAcc(url, video, baseUrlHttp, baseUrlWs, video.VideoFiles || [])
for (const playlist of (video.VideoStreamingPlaylists || [])) {
- let tag: ActivityTagObject[]
-
- tag = playlist.p2pMediaLoaderInfohashes
- .map(i => ({ type: 'Infohash' as 'Infohash', name: i }))
+ const tag = playlist.p2pMediaLoaderInfohashes
+ .map(i => ({ type: 'Infohash' as 'Infohash', name: i })) as ActivityTagObject[]
tag.push({
type: 'Link',
name: 'sha256',
}
static listForApi (options: {
- start: number,
- count: number,
- videoPlaylistId: number,
- serverAccount: AccountModel,
+ start: number
+ count: number
+ videoPlaylistId: number
+ serverAccount: AccountModel
user?: MUserAccountId
}) {
const accountIds = [ options.serverAccount.id ]
type?: VideoPlaylistType
accountId?: number
videoChannelId?: number
- listMyPlaylists?: boolean,
+ listMyPlaylists?: boolean
search?: string
}
@Scopes(() => ({
- [ ScopeNames.WITH_THUMBNAIL ]: {
+ [ScopeNames.WITH_THUMBNAIL]: {
include: [
{
model: ThumbnailModel,
}
]
},
- [ ScopeNames.WITH_VIDEOS_LENGTH ]: {
+ [ScopeNames.WITH_VIDEOS_LENGTH]: {
attributes: {
include: [
[
]
}
} as FindOptions,
- [ ScopeNames.WITH_ACCOUNT ]: {
+ [ScopeNames.WITH_ACCOUNT]: {
include: [
{
model: AccountModel,
}
]
},
- [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: {
+ [ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY]: {
include: [
{
model: AccountModel.scope(AccountScopeNames.SUMMARY),
}
]
},
- [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL ]: {
+ [ScopeNames.WITH_ACCOUNT_AND_CHANNEL]: {
include: [
{
model: AccountModel,
}
]
},
- [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => {
+ [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => {
let whereActor: WhereOptions = {}
const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId)
whereActor = {
- [ Op.or ]: [
+ [Op.or]: [
{
serverId: null
},
{
serverId: {
- [ Op.in ]: literal(inQueryInstanceFollow)
+ [Op.in]: literal(inQueryInstanceFollow)
}
}
]
if (options.search) {
whereAnd.push({
name: {
- [ Op.iLike ]: '%' + options.search + '%'
+ [Op.iLike]: '%' + options.search + '%'
}
})
}
static listForApi (options: {
followerActorId: number
- start: number,
- count: number,
- sort: string,
- type?: VideoPlaylistType,
- accountId?: number,
- videoChannelId?: number,
- listMyPlaylists?: boolean,
+ start: number
+ count: number
+ sort: string
+ type?: VideoPlaylistType
+ accountId?: number
+ videoChannelId?: number
+ listMyPlaylists?: boolean
search?: string
}) {
const query = {
}
@Scopes(() => ({
- [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
+ [ScopeNames.FOR_API]: (options: ForAPIOptions) => {
const query: FindOptions = {
include: [
{
if (options.ids) {
query.where = {
id: {
- [ Op.in ]: options.ids
+ [Op.in]: options.ids
}
}
}
return query
},
- [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => {
+ [ScopeNames.AVAILABLE_FOR_LIST_IDS]: (options: AvailableForListIDsOptions) => {
const whereAnd = options.baseWhere ? [].concat(options.baseWhere) : []
const query: FindOptions = {
const attributesType = options.attributesType || 'id'
if (attributesType === 'id') query.attributes = [ 'id' ]
- else if (attributesType === 'none') query.attributes = [ ]
+ else if (attributesType === 'none') query.attributes = []
whereAnd.push({
id: {
- [ Op.notIn ]: Sequelize.literal(
+ [Op.notIn]: Sequelize.literal(
'(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
)
}
if (options.serverAccountId) {
whereAnd.push({
channelId: {
- [ Op.notIn ]: Sequelize.literal(
+ [Op.notIn]: Sequelize.literal(
'(' +
'SELECT id FROM "videoChannel" WHERE "accountId" IN (' +
buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) +
// Only list public/published videos
if (!options.filter || options.filter !== 'all-local') {
-
const publishWhere = {
// Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding
- [ Op.or ]: [
+ [Op.or]: [
{
state: VideoState.PUBLISHED
},
{
- [ Op.and ]: {
+ [Op.and]: {
state: VideoState.TO_TRANSCODE,
waitTranscoding: false
}
[Op.or]: [
{
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
},
{
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "video"."id" AS "id" FROM "video" ' +
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
if (options.withFiles === true) {
whereAnd.push({
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(SELECT "videoId" FROM "videoFile")'
)
}
whereAnd.push({
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
whereAnd.push({
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
if (options.categoryOneOf) {
whereAnd.push({
category: {
- [ Op.or ]: options.categoryOneOf
+ [Op.or]: options.categoryOneOf
}
})
}
if (options.licenceOneOf) {
whereAnd.push({
licence: {
- [ Op.or ]: options.licenceOneOf
+ [Op.or]: options.licenceOneOf
}
})
}
[Op.or]: [
{
language: {
- [ Op.or ]: videoLanguages
+ [Op.or]: videoLanguages
}
},
{
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "videoId" FROM "videoCaption" ' +
'WHERE "language" IN (' + createSafeIn(VideoModel, options.languageOneOf) + ') ' +
}
query.where = {
- [ Op.and ]: whereAnd
+ [Op.and]: whereAnd
}
return query
},
- [ ScopeNames.WITH_THUMBNAILS ]: {
+ [ScopeNames.WITH_THUMBNAILS]: {
include: [
{
model: ThumbnailModel,
}
]
},
- [ ScopeNames.WITH_USER_ID ]: {
+ [ScopeNames.WITH_USER_ID]: {
include: [
{
attributes: [ 'accountId' ],
}
]
},
- [ ScopeNames.WITH_ACCOUNT_DETAILS ]: {
+ [ScopeNames.WITH_ACCOUNT_DETAILS]: {
include: [
{
model: VideoChannelModel.unscoped(),
}
]
},
- [ ScopeNames.WITH_TAGS ]: {
+ [ScopeNames.WITH_TAGS]: {
include: [ TagModel ]
},
- [ ScopeNames.WITH_BLACKLISTED ]: {
+ [ScopeNames.WITH_BLACKLISTED]: {
include: [
{
attributes: [ 'id', 'reason', 'unfederated' ],
}
]
},
- [ ScopeNames.WITH_WEBTORRENT_FILES ]: (withRedundancies = false) => {
+ [ScopeNames.WITH_WEBTORRENT_FILES]: (withRedundancies = false) => {
let subInclude: any[] = []
if (withRedundancies === true) {
]
}
},
- [ ScopeNames.WITH_STREAMING_PLAYLISTS ]: (withRedundancies = false) => {
+ [ScopeNames.WITH_STREAMING_PLAYLISTS]: (withRedundancies = false) => {
const subInclude: IncludeOptions[] = [
{
model: VideoFileModel.unscoped(),
]
}
},
- [ ScopeNames.WITH_SCHEDULED_UPDATE ]: {
+ [ScopeNames.WITH_SCHEDULED_UPDATE]: {
include: [
{
model: ScheduleVideoUpdateModel.unscoped(),
}
]
},
- [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => {
+ [ScopeNames.WITH_USER_HISTORY]: (userId: number) => {
return {
include: [
{
},
onDelete: 'cascade',
hooks: true,
- [ 'separate' as any ]: true
+ ['separate' as any]: true
})
VideoCaptions: VideoCaptionModel[]
order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ] as any), // FIXME: sequelize typings
where: {
id: {
- [ Op.in ]: Sequelize.literal('(' + rawQuery + ')')
+ [Op.in]: Sequelize.literal('(' + rawQuery + ')')
},
- [ Op.or ]: [
+ [Op.or]: [
{ privacy: VideoPrivacy.PUBLIC },
{ privacy: VideoPrivacy.UNLISTED }
]
required: false,
// We only want videos shared by this actor
where: {
- [ Op.and ]: [
+ [Op.and]: [
{
id: {
- [ Op.not ]: null
+ [Op.not]: null
}
},
{
// totals: totalVideos + totalVideoShares
let totalVideos = 0
let totalVideoShares = 0
- if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10)
- if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10)
+ if (totals[0]) totalVideos = parseInt(totals[0].total, 10)
+ if (totals[1]) totalVideoShares = parseInt(totals[1].total, 10)
const total = totalVideos + totalVideoShares
return {
baseQuery = Object.assign(baseQuery, {
where: {
name: {
- [ Op.iLike ]: '%' + search + '%'
+ [Op.iLike]: '%' + search + '%'
}
}
})
}
static async listForApi (options: {
- start: number,
- count: number,
- sort: string,
- nsfw: boolean,
- includeLocalVideos: boolean,
- withFiles: boolean,
- categoryOneOf?: number[],
- licenceOneOf?: number[],
- languageOneOf?: string[],
- tagsOneOf?: string[],
- tagsAllOf?: string[],
- filter?: VideoFilter,
- accountId?: number,
- videoChannelId?: number,
+ start: number
+ count: number
+ sort: string
+ nsfw: boolean
+ includeLocalVideos: boolean
+ withFiles: boolean
+ categoryOneOf?: number[]
+ licenceOneOf?: number[]
+ languageOneOf?: string[]
+ tagsOneOf?: string[]
+ tagsAllOf?: string[]
+ filter?: VideoFilter
+ accountId?: number
+ videoChannelId?: number
followerActorId?: number
- videoPlaylistId?: number,
- trendingDays?: number,
- user?: MUserAccountId,
- historyOfUser?: MUserId,
+ videoPlaylistId?: number
+ trendingDays?: number
+ user?: MUserAccountId
+ historyOfUser?: MUserId
countVideos?: boolean
}) {
if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
tagsAllOf?: string[]
durationMin?: number // seconds
durationMax?: number // seconds
- user?: MUserAccountId,
+ user?: MUserAccountId
filter?: VideoFilter
}) {
const whereAnd = []
if (options.startDate || options.endDate) {
const publishedAtRange = {}
- if (options.startDate) publishedAtRange[ Op.gte ] = options.startDate
- if (options.endDate) publishedAtRange[ Op.lte ] = options.endDate
+ if (options.startDate) publishedAtRange[Op.gte] = options.startDate
+ if (options.endDate) publishedAtRange[Op.lte] = options.endDate
whereAnd.push({ publishedAt: publishedAtRange })
}
if (options.originallyPublishedStartDate || options.originallyPublishedEndDate) {
const originallyPublishedAtRange = {}
- if (options.originallyPublishedStartDate) originallyPublishedAtRange[ Op.gte ] = options.originallyPublishedStartDate
- if (options.originallyPublishedEndDate) originallyPublishedAtRange[ Op.lte ] = options.originallyPublishedEndDate
+ if (options.originallyPublishedStartDate) originallyPublishedAtRange[Op.gte] = options.originallyPublishedStartDate
+ if (options.originallyPublishedEndDate) originallyPublishedAtRange[Op.lte] = options.originallyPublishedEndDate
whereAnd.push({ originallyPublishedAt: originallyPublishedAtRange })
}
if (options.durationMin || options.durationMax) {
const durationRange = {}
- if (options.durationMin) durationRange[ Op.gte ] = options.durationMin
- if (options.durationMax) durationRange[ Op.lte ] = options.durationMax
+ if (options.durationMin) durationRange[Op.gte] = options.durationMin
+ if (options.durationMax) durationRange[Op.lte] = options.durationMax
whereAnd.push({ duration: durationRange })
}
if (options.search) {
const trigramSearch = {
id: {
- [ Op.in ]: Sequelize.literal(
+ [Op.in]: Sequelize.literal(
'(' +
'SELECT "video"."id" FROM "video" ' +
'WHERE ' +
}
static loadForGetAPI (parameters: {
- id: number | string,
- t?: Transaction,
+ id: number | string
+ t?: Transaction
userId?: number
}): Bluebird<MVideoDetails> {
const { id, t, userId } = parameters
static checkVideoHasInstanceFollow (videoId: number, followerActorId: number) {
// Instances only share videos
const query = 'SELECT 1 FROM "videoShare" ' +
- 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
- 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' +
- 'LIMIT 1'
+ 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
+ 'WHERE "actorFollow"."actorId" = $followerActorId AND "videoShare"."videoId" = $videoId ' +
+ 'LIMIT 1'
const options = {
type: QueryTypes.SELECT as QueryTypes.SELECT,
}
return VideoModel.findAll(query)
- .then(videos => videos.map(v => v.id))
+ .then(videos => videos.map(v => v.id))
}
// threshold corresponds to how many video the field should have to be returned
limit: count,
group: field,
having: Sequelize.where(
- Sequelize.fn('COUNT', Sequelize.col(field)), { [ Op.gte ]: threshold }
+ Sequelize.fn('COUNT', Sequelize.col(field)), { [Op.gte]: threshold }
),
order: [ (this.sequelize as any).random() ]
}
return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] })
.findAll(query)
- .then(rows => rows.map(r => r[ field ]))
+ .then(rows => rows.map(r => r[field]))
}
static buildTrendingQuery (trendingDays: number) {
required: false,
where: {
startDate: {
- [ Op.gte ]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
+ [Op.gte]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
}
}
}
}
static getCategoryLabel (id: number) {
- return VIDEO_CATEGORIES[ id ] || 'Misc'
+ return VIDEO_CATEGORIES[id] || 'Misc'
}
static getLicenceLabel (id: number) {
- return VIDEO_LICENCES[ id ] || 'Unknown'
+ return VIDEO_LICENCES[id] || 'Unknown'
}
static getLanguageLabel (id: string) {
- return VIDEO_LANGUAGES[ id ] || 'Unknown'
+ return VIDEO_LANGUAGES[id] || 'Unknown'
}
static getPrivacyLabel (id: number) {
- return VIDEO_PRIVACIES[ id ] || 'Unknown'
+ return VIDEO_PRIVACIES[id] || 'Unknown'
}
static getStateLabel (id: number) {
- return VIDEO_STATES[ id ] || 'Unknown'
+ return VIDEO_STATES[id] || 'Unknown'
}
isBlacklisted () {
this.VideoChannel.Account.isBlocked()
}
- getQualityFileBy <T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) {
+ getQualityFileBy<T extends MVideoWithFile> (this: T, fun: (files: MVideoFile[], it: (file: MVideoFile) => number) => MVideoFile) {
if (Array.isArray(this.VideoFiles) && this.VideoFiles.length !== 0) {
const file = fun(this.VideoFiles, file => file.resolution)
return undefined
}
- getMaxQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
+ getMaxQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
return this.getQualityFileBy(maxBy)
}
- getMinQualityFile <T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
+ getMinQualityFile<T extends MVideoWithFile> (this: T): MVideoFileVideo | MVideoFileStreamingPlaylistVideo {
return this.getQualityFileBy(minBy)
}
- getWebTorrentFile <T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo {
+ getWebTorrentFile<T extends MVideoWithFile> (this: T, resolution: number): MVideoFileVideo {
if (Array.isArray(this.VideoFiles) === false) return undefined
const file = this.VideoFiles.find(f => f.resolution === resolution)
}
this.VideoStreamingPlaylists = this.VideoStreamingPlaylists
- .filter(s => s.type !== VideoStreamingPlaylistType.HLS)
- .concat(toAdd)
+ .filter(s => s.type !== VideoStreamingPlaylistType.HLS)
+ .concat(toAdd)
}
removeFile (videoFile: MVideoFile, isRedundancy = false) {
await remove(directoryPath)
if (isRedundancy !== true) {
- let streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo
+ const streamingPlaylistWithFiles = streamingPlaylist as MStreamingPlaylistFilesVideo
streamingPlaylistWithFiles.Video = this
if (!Array.isArray(streamingPlaylistWithFiles.VideoFiles)) {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
- killallServers,
makeActivityPubGetRequest,
ServerInfo,
setAccessTokensToServers,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
createUser,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
getVideosListSort,
- killallServers,
ServerInfo,
setAccessTokensToServers,
setActorField,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { expect } from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
await setDefaultVideoChannel(servers)
{
- videoUUID1 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video1' })).uuid
- videoUUID2 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video2' })).uuid
- videoUUID3 = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video3' })).uuid
+ videoUUID1 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video1' })).uuid
+ videoUUID2 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video2' })).uuid
+ videoUUID3 = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video3' })).uuid
}
{
- const a1 = await generateUserAccessToken(servers[ 1 ], 'user1')
- await uploadVideo(servers[ 1 ].url, a1, { name: 'video4' })
+ const a1 = await generateUserAccessToken(servers[1], 'user1')
+ await uploadVideo(servers[1].url, a1, { name: 'video4' })
- const a2 = await generateUserAccessToken(servers[ 1 ], 'user2')
- await uploadVideo(servers[ 1 ].url, a2, { name: 'video5' })
+ const a2 = await generateUserAccessToken(servers[1], 'user2')
+ await uploadVideo(servers[1].url, a2, { name: 'video5' })
}
{
- const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
- const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
+ const playlistAttrs = { displayName: 'playlist1', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
+ const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
playlistUUID1 = res.body.videoPlaylist.uuid
}
{
- const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[ 1 ].videoChannel.id }
- const res = await createVideoPlaylist({ url: servers[ 1 ].url, token: servers[ 1 ].accessToken, playlistAttrs })
+ const playlistAttrs = { displayName: 'playlist2', privacy: VideoPlaylistPrivacy.PUBLIC, videoChannelId: servers[1].videoChannel.id }
+ const res = await createVideoPlaylist({ url: servers[1].url, token: servers[1].accessToken, playlistAttrs })
playlistUUID2 = res.body.videoPlaylist.uuid
}
- await doubleFollow(servers[ 0 ], servers[ 1 ])
+ await doubleFollow(servers[0], servers[1])
})
describe('Videos refresher', function () {
await wait(10000)
// Change UUID so the remote server returns a 404
- await setVideoField(servers[ 1 ].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
+ await setVideoField(servers[1].internalServerNumber, videoUUID1, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174f')
- await getVideo(servers[ 0 ].url, videoUUID1)
- await getVideo(servers[ 0 ].url, videoUUID2)
+ await getVideo(servers[0].url, videoUUID1)
+ await getVideo(servers[0].url, videoUUID2)
await waitJobs(servers)
- await getVideo(servers[ 0 ].url, videoUUID1, 404)
- await getVideo(servers[ 0 ].url, videoUUID2, 200)
+ await getVideo(servers[0].url, videoUUID1, 404)
+ await getVideo(servers[0].url, videoUUID2, 200)
})
it('Should not update a remote video if the remote instance is down', async function () {
this.timeout(70000)
- killallServers([ servers[ 1 ] ])
+ killallServers([ servers[1] ])
- await setVideoField(servers[ 1 ].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
+ await setVideoField(servers[1].internalServerNumber, videoUUID3, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b174e')
// Video will need a refresh
await wait(10000)
- await getVideo(servers[ 0 ].url, videoUUID3)
+ await getVideo(servers[0].url, videoUUID3)
// The refresh should fail
- await waitJobs([ servers[ 0 ] ])
+ await waitJobs([ servers[0] ])
- await reRunServer(servers[ 1 ])
+ await reRunServer(servers[1])
- await getVideo(servers[ 0 ].url, videoUUID3, 200)
+ await getVideo(servers[0].url, videoUUID3, 200)
})
})
await wait(10000)
// Change actor name so the remote server returns a 404
- const to = 'http://localhost:' + servers[ 1 ].port + '/accounts/user2'
- await setActorField(servers[ 1 ].internalServerNumber, to, 'preferredUsername', 'toto')
+ const to = 'http://localhost:' + servers[1].port + '/accounts/user2'
+ await setActorField(servers[1].internalServerNumber, to, 'preferredUsername', 'toto')
- await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port)
- await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port)
+ await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port)
+ await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port)
await waitJobs(servers)
- await getAccount(servers[ 0 ].url, 'user1@localhost:' + servers[ 1 ].port, 200)
- await getAccount(servers[ 0 ].url, 'user2@localhost:' + servers[ 1 ].port, 404)
+ await getAccount(servers[0].url, 'user1@localhost:' + servers[1].port, 200)
+ await getAccount(servers[0].url, 'user2@localhost:' + servers[1].port, 404)
})
})
await wait(10000)
// Change UUID so the remote server returns a 404
- await setPlaylistField(servers[ 1 ].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
+ await setPlaylistField(servers[1].internalServerNumber, playlistUUID2, 'uuid', '304afe4f-39f9-4d49-8ed7-ac57b86b178e')
- await getVideoPlaylist(servers[ 0 ].url, playlistUUID1)
- await getVideoPlaylist(servers[ 0 ].url, playlistUUID2)
+ await getVideoPlaylist(servers[0].url, playlistUUID1)
+ await getVideoPlaylist(servers[0].url, playlistUUID2)
await waitJobs(servers)
- await getVideoPlaylist(servers[ 0 ].url, playlistUUID1, 200)
- await getVideoPlaylist(servers[ 0 ].url, playlistUUID2, 404)
+ await getVideoPlaylist(servers[0].url, playlistUUID1, 200)
+ await getVideoPlaylist(servers[0].url, playlistUUID2, 404)
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-import {
- cleanupTests,
- closeAllSequelize,
- flushAndRunMultipleServers,
- killallServers,
- ServerInfo,
- setActorField
-} from '../../../../shared/extra-utils'
+import { cleanupTests, closeAllSequelize, flushAndRunMultipleServers, ServerInfo, setActorField } from '../../../../shared/extra-utils'
import { HTTP_SIGNATURE } from '../../../initializers/constants'
import { buildDigest, buildGlobalHeaders } from '../../../lib/job-queue/handlers/utils/activitypub-http-utils'
import * as chai from 'chai'
if (Array.isArray(json[key])) {
result[key] = json[key].map(v => v.replace(':9002', `:${server2.port}`))
} else {
- result[ key ] = json[ key ].replace(':9002', `:${server2.port}`)
+ result[key] = json[key].replace(':9002', `:${server2.port}`)
}
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { omit } from 'lodash'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-import {
- flushTests,
- immutableAssign,
- killallServers,
- reRunServer,
- flushAndRunServer,
- ServerInfo,
- setAccessTokensToServers, cleanupTests
-} from '../../../../shared/extra-utils'
-import {
- checkBadCountPagination,
- checkBadSortPagination,
- checkBadStartPagination
-} from '../../../../shared/extra-utils/requests/check-api-params'
-import { getAccount } from '../../../../shared/extra-utils/users/accounts'
+import { cleanupTests, flushAndRunServer, immutableAssign, killallServers, reRunServer, ServerInfo } from '../../../../shared/extra-utils'
import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
+ cleanupTests,
createUser,
- flushTests,
- killallServers,
flushAndRunServer,
ServerInfo,
setAccessTokensToServers,
- userLogin, cleanupTests
+ userLogin
} from '../../../../shared/extra-utils'
import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
+ cleanupTests,
createUser,
- flushTests,
- killallServers,
flushAndRunServer,
ServerInfo,
setAccessTokensToServers,
- userLogin,
- cleanupTests
+ userLogin
} from '../../../../shared/extra-utils'
import {
checkBadCountPagination,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
+ cleanupTests,
createUser,
- flushTests,
- killallServers,
flushAndRunServer,
ServerInfo,
setAccessTokensToServers,
- userLogin,
- cleanupTests
+ userLogin
} from '../../../../shared/extra-utils'
import { makeGetRequest } from '../../../../shared/extra-utils/requests/requests'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
password: 'password'
}
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
userAccessToken = await userLogin(servers[0], user)
videoIdLocal = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video' })).id
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as io from 'socket.io-client'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { omit } from 'lodash'
import 'mocha'
let serverWithRegistrationDisabled: ServerInfo
let userAccessToken = ''
let moderatorAccessToken = ''
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let channelId: number
// ---------------------------------------------------------------
{
const res = await getMyUserInformation(server.url, server.accessToken)
- channelId = res.body.videoChannels[ 0 ].id
+ channelId = res.body.videoChannels[0].id
}
{
it('Should fail without an incorrect input file', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
})
it('Should fail with a big file', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({ url: server.url, path: path + '/me/avatar/pick', token: server.accessToken, fields, attaches })
})
it('Should fail with an unauthenticated user', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
url: server.url,
it('Should succeed with the correct params', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
url: server.url,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
describe('When updating a video abuse', function () {
const basePath = '/api/v1/videos/'
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let path: string
before(() => {
describe('When deleting a video abuse', function () {
const basePath = '/api/v1/videos/'
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let path: string
before(() => {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
createUser,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
getBlacklistedVideosList,
getVideo,
getVideoWithToken,
- killallServers,
makePostBodyRequest,
makePutBodyRequest,
removeVideoFromBlacklist,
ServerInfo,
setAccessTokensToServers,
uploadVideo,
- userLogin, waitJobs
+ userLogin,
+ waitJobs
} from '../../../../shared/extra-utils'
import {
checkBadCountPagination,
checkBadSortPagination,
checkBadStartPagination
} from '../../../../shared/extra-utils/requests/check-api-params'
-import { VideoDetails, VideoBlacklistType } from '../../../../shared/models/videos'
+import { VideoBlacklistType, VideoDetails } from '../../../../shared/models/videos'
import { expect } from 'chai'
describe('Test video blacklist API validators', function () {
{
const username = 'user1'
const password = 'my super password'
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password })
userAccessToken1 = await userLogin(servers[0], { username, password })
}
{
const username = 'user2'
const password = 'my super password'
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: username, password: password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: username, password: password })
userAccessToken2 = await userLogin(servers[0], { username, password })
}
it('Should succeed with the correct params', async function () {
const path = basePath + servers[0].video.uuid + '/blacklist'
- const fields = { }
+ const fields = {}
await makePostBodyRequest({ url: servers[0].url, path, token: servers[0].accessToken, fields, statusCodeExpected: 204 })
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
describe('When adding video caption', function () {
const fields = { }
const attaches = {
- 'captionfile': join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt')
+ captionfile: join(__dirname, '..', '..', 'fixtures', 'subtitle-good1.vtt')
}
it('Should fail without a valid uuid', async function () {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import { omit } from 'lodash'
it('Should fail with an incorrect input file', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches })
})
it('Should fail with a big file', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({ url: server.url, path: path + '/avatar/pick', token: server.accessToken, fields, attaches })
})
it('Should fail with an unauthenticated user', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
url: server.url,
it('Should succeed with the correct params', async function () {
const fields = {}
const attaches = {
- 'avatarfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ avatarfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
url: server.url,
})
it('Should fail with an unknown video channel id', async function () {
- await deleteVideoChannel(server.url, server.accessToken,'super_channel2', 404)
+ await deleteVideoChannel(server.url, server.accessToken, 'super_channel2', 404)
})
it('Should succeed with the correct parameters', async function () {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { omit } from 'lodash'
import 'mocha'
const path = '/api/v1/videos/imports'
let server: ServerInfo
let userAccessToken = ''
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let accountName: string
let channelId: number
{
const res = await getMyUserInformation(server.url, server.accessToken)
- channelId = res.body.videoChannels[ 0 ].id
+ channelId = res.body.videoChannels[0].id
accountName = res.body.account.name + '@' + res.body.account.host
}
})
it('Should fail with an incorrect thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
it('Should fail with a big thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
+ thumbnailfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
it('Should fail with an incorrect preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar.png')
+ previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar.png')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
it('Should fail with a big preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
+ previewfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
it('Should fail with an invalid torrent file', async function () {
const fields = omit(baseCorrectParams, 'targetUrl')
const attaches = {
- 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
+ torrentfile: join(__dirname, '..', '..', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches })
fields = omit(fields, 'magnetUri')
const attaches = {
- 'torrentfile': join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent')
+ torrentfile: join(__dirname, '..', '..', 'fixtures', 'video-720p.torrent')
}
await makeUploadRequest({ url: server.url, path, token: server.accessToken, fields, attaches, statusCodeExpected: 409 })
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
let privatePlaylistUUID: string
let watchLaterPlaylistId: number
let videoId: number
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let videoId2: number
let playlistElementId: number
videoId3 = (await uploadVideoAndGetId({ server, videoName: 'video 3' })).id
videoId4 = (await uploadVideoAndGetId({ server, videoName: 'video 4' })).id
- for (let id of [ videoId3, videoId4 ]) {
+ for (const id of [ videoId3, videoId4 ]) {
await addVideoInPlaylist({
url: server.url,
token: server.accessToken,
}
{
- const params = getBase({}, { playlistId: 42, expectedStatus: 404 })
+ const params = getBase({}, { playlistId: 42, expectedStatus: 404 })
await reorderVideosPlaylist(params)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
cleanupTests,
createUser,
- createVideoPlaylist,
flushAndRunServer,
makeGetRequest,
ServerInfo,
userLogin
} from '../../../../shared/extra-utils'
import { UserRole } from '../../../../shared/models/users'
-import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
async function testEndpoints (server: ServerInfo, token: string, filter: string, statusCodeExpected: number) {
const paths = [
})
it('Should succeed with a good filter', async function () {
- await testEndpoints(server, server.accessToken,'local', 200)
+ await testEndpoints(server, server.accessToken, 'local', 200)
})
it('Should fail to list all-local with a simple user', async function () {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
-import * as chai from 'chai'
import 'mocha'
import {
checkBadCountPagination,
uploadVideo
} from '../../../../shared/extra-utils'
-const expect = chai.expect
-
describe('Test videos history API validator', function () {
+ const myHistoryPath = '/api/v1/users/me/history/videos'
+ const myHistoryRemove = myHistoryPath + '/remove'
let watchingPath: string
- let myHistoryPath = '/api/v1/users/me/history/videos'
- let myHistoryRemove = myHistoryPath + '/remove'
let server: ServerInfo
// ---------------------------------------------------------------
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import { omit } from 'lodash'
{
const res = await getMyUserInformation(server.url, server.accessToken)
- channelId = res.body.videoChannels[ 0 ].id
- channelName = res.body.videoChannels[ 0 ].name
+ channelId = res.body.videoChannels[0].id
+ channelName = res.body.videoChannels[0].name
accountName = res.body.account.name + '@' + res.body.account.host
}
})
describe('When adding a video', function () {
let baseCorrectParams
const baseCorrectAttaches = {
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.webm')
}
before(function () {
})
it('Should fail with a bad originally published at attribute', async function () {
- const fields = immutableAssign(baseCorrectParams, { 'originallyPublishedAt': 'toto' })
+ const fields = immutableAssign(baseCorrectParams, { originallyPublishedAt: 'toto' })
const attaches = baseCorrectAttaches
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
it('Should fail with an incorrect input file', async function () {
const fields = baseCorrectParams
let attaches = {
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm')
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short_fake.webm')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
attaches = {
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv')
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mkv')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
})
it('Should fail with an incorrect thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
+ thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
it('Should fail with a big thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
+ thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
it('Should fail with an incorrect preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
+ previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png'),
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
it('Should fail with a big preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
- 'videofile': join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
+ previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png'),
+ videofile: join(root(), 'server', 'tests', 'fixtures', 'video_short.mp4')
}
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
it('Should fail with an incorrect thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
+ thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
it('Should fail with a big thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'thumbnailfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
+ thumbnailfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({
it('Should fail with an incorrect preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
+ previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar.png')
}
await makeUploadRequest({
it('Should fail with a big preview file', async function () {
const fields = baseCorrectParams
const attaches = {
- 'previewfile': join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
+ previewfile: join(root(), 'server', 'tests', 'fixtures', 'avatar-big.png')
}
await makeUploadRequest({
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
const name = 'remote video ' + uuidv4()
const data = Object.assign({ name }, additionalParams)
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, data)
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, data)
await waitJobs(servers)
const name = 'local video ' + uuidv4()
const data = Object.assign({ name }, additionalParams)
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, data)
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, data)
await waitJobs(servers)
describe('Test users notifications', function () {
let servers: ServerInfo[] = []
let userAccessToken: string
- let userNotifications: UserNotification[] = []
- let adminNotifications: UserNotification[] = []
- let adminNotificationsServer2: UserNotification[] = []
+ const userNotifications: UserNotification[] = []
+ const adminNotifications: UserNotification[] = []
+ const adminNotificationsServer2: UserNotification[] = []
const emails: object[] = []
let channelId: number
password: 'super password'
}
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: user.username,
password: user.password,
videoQuota: 10 * 1000 * 1000
await updateMyNotificationSettings(servers[1].url, servers[1].accessToken, allNotificationSettings)
{
- const socket = getUserNotificationSocket(servers[ 0 ].url, userAccessToken)
+ const socket = getUserNotificationSocket(servers[0].url, userAccessToken)
socket.on('new-notification', n => userNotifications.push(n))
}
{
- const socket = getUserNotificationSocket(servers[ 0 ].url, servers[0].accessToken)
+ const socket = getUserNotificationSocket(servers[0].url, servers[0].accessToken)
socket.on('new-notification', n => adminNotifications.push(n))
}
{
- const socket = getUserNotificationSocket(servers[ 1 ].url, servers[1].accessToken)
+ const socket = getUserNotificationSocket(servers[1].url, servers[1].accessToken)
socket.on('new-notification', n => adminNotificationsServer2.push(n))
}
await uploadVideoByLocalAccount(servers)
- const notification = await getLastNotification(servers[ 0 ].url, userAccessToken)
+ const notification = await getLastNotification(servers[0].url, userAccessToken)
expect(notification).to.be.undefined
expect(emails).to.have.lengthOf(0)
this.timeout(20000)
// In 2 seconds
- let updateAt = new Date(new Date().getTime() + 2000)
+ const updateAt = new Date(new Date().getTime() + 2000)
const data = {
privacy: VideoPrivacy.PRIVATE,
this.timeout(50000)
// In 2 seconds
- let updateAt = new Date(new Date().getTime() + 2000)
+ const updateAt = new Date(new Date().getTime() + 2000)
const data = {
privacy: VideoPrivacy.PRIVATE,
it('Should not send a notification before the video is published', async function () {
this.timeout(20000)
- let updateAt = new Date(new Date().getTime() + 1000000)
+ const updateAt = new Date(new Date().getTime() + 1000000)
const data = {
privacy: VideoPrivacy.PRIVATE,
it('Should not send a new comment notification if the account is muted', async function () {
this.timeout(10000)
- await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root')
+ await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root')
const resVideo = await uploadVideo(servers[0].url, userAccessToken, { name: 'super video' })
const uuid = resVideo.body.video.uuid
await wait(500)
await checkNewCommentOnMyVideo(baseParams, uuid, commentId, commentId, 'absence')
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root')
+ await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root')
})
it('Should send a new comment notification after a local comment on my video', async function () {
await waitJobs(servers)
{
- const resThread = await addVideoCommentThread(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, 'comment')
+ const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, 'comment')
const threadId = resThread.body.comment.id
- await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, uuid, threadId, 'reply')
+ await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, threadId, 'reply')
}
await waitJobs(servers)
it('Should not send a new mention notification if the account is muted', async function () {
this.timeout(10000)
- await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root')
+ await addAccountToAccountBlocklist(servers[0].url, userAccessToken, 'root')
const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'super video' })
const uuid = resVideo.body.video.uuid
await wait(500)
await checkCommentMention(baseParams, uuid, commentId, commentId, 'super root name', 'absence')
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessToken, 'root')
+ await removeAccountFromAccountBlocklist(servers[0].url, userAccessToken, 'root')
})
it('Should not send a new mention notification if the remote account mention a local account', async function () {
await waitJobs(servers)
- const text1 = `hello @user_1@localhost:${servers[ 0 ].port} 1`
+ const text1 = `hello @user_1@localhost:${servers[0].port} 1`
const resThread = await addVideoCommentThread(servers[1].url, servers[1].accessToken, uuid, text1)
const server2ThreadId = resThread.body.comment.id
const server1ThreadId = resThread2.body.data[0].id
await checkCommentMention(baseParams, uuid, server1ThreadId, server1ThreadId, 'super root 2 name', 'presence')
- const text2 = `@user_1@localhost:${servers[ 0 ].port} hello 2 @root@localhost:${servers[ 0 ].port}`
+ const text2 = `@user_1@localhost:${servers[0].port} hello 2 @root@localhost:${servers[0].port}`
await addVideoCommentReply(servers[1].url, servers[1].accessToken, uuid, server2ThreadId, text2)
await waitJobs(servers)
})
})
- describe('Video abuse for moderators notification' , function () {
+ describe('Video abuse for moderators notification', function () {
let baseParams: CheckerBaseParams
before(() => {
await uploadVideoByRemoteAccount(servers, { waitTranscoding: false })
await waitJobs(servers)
- const notification = await getLastNotification(servers[ 0 ].url, userAccessToken)
+ const notification = await getLastNotification(servers[0].url, userAccessToken)
if (notification) {
expect(notification.type).to.not.equal(UserNotificationType.MY_VIDEO_PUBLISHED)
}
this.timeout(70000)
// In 2 seconds
- let updateAt = new Date(new Date().getTime() + 2000)
+ const updateAt = new Date(new Date().getTime() + 2000)
const data = {
privacy: VideoPrivacy.PRIVATE,
it('Should not send a notification before the video is published', async function () {
this.timeout(20000)
- let updateAt = new Date(new Date().getTime() + 1000000)
+ const updateAt = new Date(new Date().getTime() + 1000000)
const data = {
privacy: VideoPrivacy.PRIVATE,
describe('New actor follow', function () {
let baseParams: CheckerBaseParams
- let myChannelName = 'super channel name'
- let myUserName = 'super user name'
+ const myChannelName = 'super channel name'
+ const myUserName = 'super user name'
before(async () => {
baseParams = {
it('Should send unblacklist but not published/subscription notes after unblacklisted if scheduled update pending', async function () {
this.timeout(20000)
- let updateAt = new Date(new Date().getTime() + 1000000)
+ const updateAt = new Date(new Date().getTime() + 1000000)
const name = 'video with auto-blacklist and future schedule ' + uuidv4()
this.timeout(20000)
// In 2 seconds
- let updateAt = new Date(new Date().getTime() + 2000)
+ const updateAt = new Date(new Date().getTime() + 2000)
const name = 'video with schedule done and still auto-blacklisted ' + uuidv4()
describe('Mark as read', function () {
it('Should mark as read some notifications', async function () {
- const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 2, 3)
+ const res = await getUserNotifications(servers[0].url, userAccessToken, 2, 3)
const ids = res.body.data.map(n => n.id)
- await markAsReadNotifications(servers[ 0 ].url, userAccessToken, ids)
+ await markAsReadNotifications(servers[0].url, userAccessToken, ids)
})
it('Should have the notifications marked as read', async function () {
- const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10)
+ const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10)
const notifications = res.body.data as UserNotification[]
- expect(notifications[ 0 ].read).to.be.false
- expect(notifications[ 1 ].read).to.be.false
- expect(notifications[ 2 ].read).to.be.true
- expect(notifications[ 3 ].read).to.be.true
- expect(notifications[ 4 ].read).to.be.true
- expect(notifications[ 5 ].read).to.be.false
+ expect(notifications[0].read).to.be.false
+ expect(notifications[1].read).to.be.false
+ expect(notifications[2].read).to.be.true
+ expect(notifications[3].read).to.be.true
+ expect(notifications[4].read).to.be.true
+ expect(notifications[5].read).to.be.false
})
it('Should only list read notifications', async function () {
- const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, false)
+ const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, false)
const notifications = res.body.data as UserNotification[]
for (const notification of notifications) {
})
it('Should only list unread notifications', async function () {
- const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true)
+ const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true)
const notifications = res.body.data as UserNotification[]
for (const notification of notifications) {
})
it('Should mark as read all notifications', async function () {
- await markAsReadAllNotifications(servers[ 0 ].url, userAccessToken)
+ await markAsReadAllNotifications(servers[0].url, userAccessToken)
- const res = await getUserNotifications(servers[ 0 ].url, userAccessToken, 0, 10, true)
+ const res = await getUserNotifications(servers[0].url, userAccessToken, 0, 10, true)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
await setAccessTokensToServers(servers)
{
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' })
video1Server2UUID = res.body.video.uuid
}
{
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' })
video2Server2UUID = res.body.video.uuid
}
await waitJobs(servers)
// Server 1 and server 2 follow each other
- await doubleFollow(servers[ 0 ], servers[ 1 ])
- await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true)
+ await doubleFollow(servers[0], servers[1])
+ await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true)
await waitJobs(servers)
})
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 1 server 2')
- expect(videos[ 1 ].name).to.equal('video 2 server 2')
+ expect(videos[0].name).to.equal('video 1 server 2')
+ expect(videos[1].name).to.equal('video 2 server 2')
}
{
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 2 server 2')
- expect(videos[ 1 ].name).to.equal('video 1 server 2')
+ expect(videos[0].name).to.equal('video 2 server 2')
+ expect(videos[1].name).to.equal('video 1 server 2')
}
{
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 1 server 2')
+ expect(videos[0].name).to.equal('video 1 server 2')
}
})
it('Should manually add a redundancy and list it', async function () {
this.timeout(120000)
- const uuid = (await uploadVideoAndGetId({ server: servers[ 1 ], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid
+ const uuid = (await uploadVideoAndGetId({ server: servers[1], videoName: 'video 3 server 2', privacy: VideoPrivacy.UNLISTED })).uuid
await waitJobs(servers)
const videoId = await getLocalIdByUUID(servers[0].url, uuid)
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 3 server 2')
+ expect(videos[0].name).to.equal('video 3 server 2')
- const video = videos[ 0 ]
+ const video = videos[0]
expect(video.redundancies.files).to.have.lengthOf(4)
expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 3 server 2')
+ expect(videos[0].name).to.equal('video 3 server 2')
- const video = videos[ 0 ]
+ const video = videos[0]
expect(video.redundancies.files).to.have.lengthOf(4)
expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
for (const redundancyId of redundanciesToRemove) {
await removeVideoRedundancy({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
redundancyId
})
}
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('video 2 server 2')
+ expect(videos[0].name).to.equal('video 2 server 2')
redundanciesToRemove = []
- const video = videos[ 0 ]
+ const video = videos[0]
expect(video.redundancies.files).to.have.lengthOf(4)
expect(video.redundancies.streamingPlaylists).to.have.lengthOf(1)
{
for (const redundancyId of redundanciesToRemove) {
await removeVideoRedundancy({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
redundancyId
})
}
})
const videos = res.body.data
- expect(videos[ 0 ].name).to.equal('video 1 server 2')
+ expect(videos[0].name).to.equal('video 1 server 2')
expect(videos).to.have.lengthOf(1)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
await setAccessTokensToServers(servers)
{
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 server 2' })
video1Server2UUID = res.body.video.uuid
video1Server2Id = res.body.video.id
- await viewVideo(servers[ 1 ].url, video1Server2UUID)
+ await viewVideo(servers[1].url, video1Server2UUID)
}
await waitJobs(servers)
// Server 1 and server 2 follow each other
- await doubleFollow(servers[ 0 ], servers[ 1 ])
+ await doubleFollow(servers[0], servers[1])
// Server 1 and server 3 follow each other
- await doubleFollow(servers[ 0 ], servers[ 2 ])
+ await doubleFollow(servers[0], servers[2])
// Server 2 and server 3 follow each other
- await doubleFollow(servers[ 1 ], servers[ 2 ])
+ await doubleFollow(servers[1], servers[2])
await waitJobs(servers)
}
if (!videoUUID) videoUUID = video1Server2UUID
const webseeds = [
- `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
+ `http://localhost:${servers[1].port}/static/webseed/${videoUUID}`
]
for (const server of servers) {
if (!videoUUID) videoUUID = video1Server2UUID
const webseeds = [
- `http://localhost:${servers[ 0 ].port}/static/redundancy/${videoUUID}`,
- `http://localhost:${servers[ 1 ].port}/static/webseed/${videoUUID}`
+ `http://localhost:${servers[0].port}/static/redundancy/${videoUUID}`,
+ `http://localhost:${servers[1].port}/static/webseed/${videoUUID}`
]
for (const server of servers) {
}
async function enableRedundancyOnServer1 () {
- await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, true)
+ await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, true)
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' })
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' })
const follows: ActorFollow[] = res.body.data
- const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
- const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
+ const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
+ const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
expect(server3).to.not.be.undefined
expect(server3.following.hostRedundancyAllowed).to.be.false
}
async function disableRedundancyOnServer1 () {
- await updateRedundancy(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ].host, false)
+ await updateRedundancy(servers[0].url, servers[0].accessToken, servers[1].host, false)
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: '-createdAt' })
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: '-createdAt' })
const follows: ActorFollow[] = res.body.data
- const server2 = follows.find(f => f.following.host === `localhost:${servers[ 1 ].port}`)
- const server3 = follows.find(f => f.following.host === `localhost:${servers[ 2 ].port}`)
+ const server2 = follows.find(f => f.following.host === `localhost:${servers[1].port}`)
+ const server3 = follows.find(f => f.following.host === `localhost:${servers[2].port}`)
expect(server3).to.not.be.undefined
expect(server3.following.hostRedundancyAllowed).to.be.false
it('Should view 2 times the first video to have > min_views config', async function () {
this.timeout(80000)
- await viewVideo(servers[ 0 ].url, video1Server2UUID)
- await viewVideo(servers[ 2 ].url, video1Server2UUID)
+ await viewVideo(servers[0].url, video1Server2UUID)
+ await viewVideo(servers[2].url, video1Server2UUID)
await wait(10000)
await waitJobs(servers)
await check1PlaylistRedundancies()
await checkStatsWith2Webseed(strategy)
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 2 server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 2 server 2' })
video2Server2UUID = res.body.video.uuid
})
await waitJobs(servers)
- killallServers([ servers[ 0 ] ])
- await reRunServer(servers[ 0 ], {
+ killallServers([ servers[0] ])
+ await reRunServer(servers[0], {
redundancy: {
videos: {
check_interval: '1 second',
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
await setAccessTokensToServers(servers)
{
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'user1_server1', password: 'password' })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'user1_server1', password: 'password' })
const channel = {
name: 'channel1_server1',
displayName: 'Channel 1 server 1'
{
const user = { username: 'user1_server2', password: 'password' }
- await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
userServer2Token = await userLogin(servers[1], user)
const channel = {
this.timeout(15000)
{
- const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server3'
- const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
+ const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server3'
+ const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
{
// Without token
- const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
const res = await searchVideoChannel(servers[0].url, search)
expect(res.body.total).to.equal(0)
it('Should search a local video channel', async function () {
const searches = [
- 'http://localhost:' + servers[ 0 ].port + '/video-channels/channel1_server1',
- 'channel1_server1@localhost:' + servers[ 0 ].port
+ 'http://localhost:' + servers[0].port + '/video-channels/channel1_server1',
+ 'channel1_server1@localhost:' + servers[0].port
]
for (const search of searches) {
- const res = await searchVideoChannel(servers[ 0 ].url, search)
+ const res = await searchVideoChannel(servers[0].url, search)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
- expect(res.body.data[ 0 ].name).to.equal('channel1_server1')
- expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 1')
+ expect(res.body.data[0].name).to.equal('channel1_server1')
+ expect(res.body.data[0].displayName).to.equal('Channel 1 server 1')
}
})
it('Should search a remote video channel with URL or handle', async function () {
const searches = [
- 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2',
- 'channel1_server2@localhost:' + servers[ 1 ].port
+ 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2',
+ 'channel1_server2@localhost:' + servers[1].port
]
for (const search of searches) {
- const res = await searchVideoChannel(servers[ 0 ].url, search, servers[ 0 ].accessToken)
+ const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
- expect(res.body.data[ 0 ].name).to.equal('channel1_server2')
- expect(res.body.data[ 0 ].displayName).to.equal('Channel 1 server 2')
+ expect(res.body.data[0].name).to.equal('channel1_server2')
+ expect(res.body.data[0].displayName).to.equal('Channel 1 server 2')
}
})
await waitJobs(servers)
- const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
+ const res = await getVideoChannelVideos(servers[0].url, null, 'channel1_server2@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
})
it('Should list video channel videos of server 2 with token', async function () {
- const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[ 1 ].port, 0, 5)
+ const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, 'channel1_server2@localhost:' + servers[1].port, 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data[0].name).to.equal('video 1 server 2')
// Expire video channel
await wait(10000)
- const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
// Expire video channel
await wait(10000)
- const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
await waitJobs(servers)
- const videoChannelName = 'channel1_server2@localhost:' + servers[ 1 ].port
+ const videoChannelName = 'channel1_server2@localhost:' + servers[1].port
const res = await getVideoChannelVideos(servers[0].url, servers[0].accessToken, videoChannelName, 0, 5, '-createdAt')
expect(res.body.total).to.equal(2)
// Expire video
await wait(10000)
- const search = 'http://localhost:' + servers[ 1 ].port + '/video-channels/channel1_server2'
+ const search = 'http://localhost:' + servers[1].port + '/video-channels/channel1_server2'
const res = await searchVideoChannel(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.have.lengthOf(0)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
await setAccessTokensToServers(servers)
{
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1 on server 1' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1 on server 1' })
videoServer1UUID = res.body.video.uuid
}
{
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video 1 on server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video 1 on server 2' })
videoServer2UUID = res.body.video.uuid
}
it('Should not find a remote video', async function () {
{
const search = 'http://localhost:' + servers[1].port + '/videos/watch/43'
- const res = await searchVideoWithToken(servers[ 0 ].url, search, servers[ 0 ].accessToken)
+ const res = await searchVideoWithToken(servers[0].url, search, servers[0].accessToken)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
const attributes5 = immutableAssign(attributes1, { name: attributes1.name + ' - 5', licence: 2, language: undefined })
await uploadVideo(server.url, server.accessToken, attributes5)
- const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2 '] })
+ const attributes6 = immutableAssign(attributes1, { name: attributes1.name + ' - 6', tags: [ 't1', 't2' ] })
await uploadVideo(server.url, server.accessToken, attributes6)
const attributes7 = immutableAssign(attributes1, {
{
const res = await advancedVideosSearch(server.url, query)
expect(res.body.total).to.equal(2)
- expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3')
- expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4')
+ expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3')
+ expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4')
}
{
const res = await advancedVideosSearch(server.url, immutableAssign(query, { languageOneOf: [ 'pl', 'en', '_unknown' ] }))
expect(res.body.total).to.equal(3)
- expect(res.body.data[ 0 ].name).to.equal('1111 2222 3333 - 3')
- expect(res.body.data[ 1 ].name).to.equal('1111 2222 3333 - 4')
- expect(res.body.data[ 2 ].name).to.equal('1111 2222 3333 - 5')
+ expect(res.body.data[0].name).to.equal('1111 2222 3333 - 3')
+ expect(res.body.data[1].name).to.equal('1111 2222 3333 - 4')
+ expect(res.body.data[2].name).to.equal('1111 2222 3333 - 5')
}
{
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
async function resetFollows (servers: ServerInfo[]) {
try {
- await unfollow(servers[ 0 ].url, servers[ 0 ].accessToken, servers[ 1 ])
- await unfollow(servers[ 1 ].url, servers[ 1 ].accessToken, servers[ 0 ])
- } catch { /* empty */ }
+ await unfollow(servers[0].url, servers[0].accessToken, servers[1])
+ await unfollow(servers[1].url, servers[1].accessToken, servers[0])
+ } catch { /* empty */
+ }
await waitJobs(servers)
await wait(5000)
await waitJobs(servers)
- await checkFollow(servers[ 0 ], servers[ 1 ], false)
- await checkFollow(servers[ 1 ], servers[ 0 ], false)
+ await checkFollow(servers[0], servers[1], false)
+ await checkFollow(servers[1], servers[0], false)
})
it('Should auto follow the index', async function () {
await wait(5000)
await waitJobs(servers)
- await checkFollow(servers[ 0 ], servers[ 1 ], true)
+ await checkFollow(servers[0], servers[1], true)
await resetFollows(servers)
})
await wait(5000)
await waitJobs(servers)
- await checkFollow(servers[ 0 ], servers[ 1 ], false)
- await checkFollow(servers[ 0 ], servers[ 2 ], true)
+ await checkFollow(servers[0], servers[1], false)
+ await checkFollow(servers[0], servers[2], true)
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
getAbout,
getConfig,
getCustomConfig,
- killallServers, parallelTests,
+ killallServers,
+ parallelTests,
registerUser,
- reRunServer, ServerInfo,
+ reRunServer,
+ ServerInfo,
setAccessTokensToServers,
- updateCustomConfig, uploadVideo
+ updateCustomConfig,
+ uploadVideo
} from '../../../../shared/extra-utils'
import { ServerConfig } from '../../../../shared/models'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-import {
- flushTests,
- killallServers,
- flushAndRunServer,
- ServerInfo,
- setAccessTokensToServers,
- wait,
- cleanupTests
-} from '../../../../shared/extra-utils'
+import { cleanupTests, flushAndRunServer, ServerInfo, setAccessTokensToServers, wait } from '../../../../shared/extra-utils'
import { MockSmtpServer } from '../../../../shared/extra-utils/miscs/email'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { sendContactForm } from '../../../../shared/extra-utils/server/contact-form'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
await setAccessTokensToServers(servers)
{
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video server 1' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video server 1' })
video1UUID = res.body.video.uuid
}
{
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video server 2' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video server 2' })
video2UUID = res.body.video.uuid
}
username: 'user1',
password: 'super_password'
}
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
userAccessToken = await userLogin(servers[0], user)
await doubleFollow(servers[0], servers[1])
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
async function checkServer1And2HasFollowers (servers: ServerInfo[], state = 'accepted') {
{
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(1)
const follow = res.body.data[0] as ActorFollow
}
{
- const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(1)
const follow = res.body.data[0] as ActorFollow
async function checkNoFollowers (servers: ServerInfo[]) {
{
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(0)
}
{
- const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(0)
}
}
await waitJobs(servers)
{
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(2)
}
{
- const res = await getFollowersListPaginationAndSort({ url: servers[ 1 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[1].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(1)
}
{
- const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(1)
}
await checkServer1And2HasFollowers(servers)
{
- const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 5, sort: 'createdAt' })
expect(res.body.total).to.equal(0)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
})
it('Should have 2 followings on server 1', async function () {
- let res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 1, sort: 'createdAt' })
+ let res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 1, sort: 'createdAt' })
let follows = res.body.data
expect(res.body.total).to.equal(2)
expect(follows).to.be.an('array')
expect(follows.length).to.equal(1)
- res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 1, count: 1, sort: 'createdAt' })
+ res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 1, count: 1, sort: 'createdAt' })
follows = follows.concat(res.body.data)
const server2Follow = follows.find(f => f.following.host === 'localhost:' + servers[1].port)
const sort = 'createdAt'
const start = 0
const count = 1
- const url = servers[ 0 ].url
+ const url = servers[0].url
{
const search = ':' + servers[1].port
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
- expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 1 ].port)
+ expect(follows[0].following.host).to.equal('localhost:' + servers[1].port)
}
{
it('Should have 1 followers on server 2 and 3', async function () {
for (const server of [ servers[1], servers[2] ]) {
- let res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: server.url, start: 0, count: 1, sort: 'createdAt' })
- let follows = res.body.data
+ const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows).to.be.an('array')
expect(follows.length).to.equal(1)
})
it('Should search/filter followers on server 2', async function () {
- const url = servers[ 2 ].url
+ const url = servers[2].url
const start = 0
const count = 5
const sort = 'createdAt'
expect(res.body.total).to.equal(1)
expect(follows.length).to.equal(1)
- expect(follows[ 0 ].following.host).to.equal('localhost:' + servers[ 2 ].port)
+ expect(follows[0].following.host).to.equal('localhost:' + servers[2].port)
}
{
})
it('Should have 0 followers on server 1', async function () {
- const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 5, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 5, sort: 'createdAt' })
const follows = res.body.data
expect(res.body.total).to.equal(0)
})
it('Should not follow server 3 on server 1 anymore', async function () {
- const res = await getFollowingListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
- let follows = res.body.data
+ const res = await getFollowingListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
+ const follows = res.body.data
expect(res.body.total).to.equal(1)
expect(follows).to.be.an('array')
})
it('Should not have server 1 as follower on server 3 anymore', async function () {
- const res = await getFollowersListPaginationAndSort({ url: servers[ 2 ].url, start: 0, count: 1, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[2].url, start: 0, count: 1, sort: 'createdAt' })
- let follows = res.body.data
+ const follows = res.body.data
expect(res.body.total).to.equal(0)
expect(follows).to.be.an('array')
expect(follows.length).to.equal(0)
tags: [ 'tag1', 'tag2', 'tag3' ]
}
- await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-2' })
- await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-3' })
- await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4Attributes)
- await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-5' })
- await uploadVideo(servers[ 2 ].url, servers[ 2 ].accessToken, { name: 'server3-6' })
+ await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-2' })
+ await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-3' })
+ await uploadVideo(servers[2].url, servers[2].accessToken, video4Attributes)
+ await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-5' })
+ await uploadVideo(servers[2].url, servers[2].accessToken, { name: 'server3-6' })
{
const user = { username: 'captain', password: 'password' }
- await createUser({ url: servers[ 2 ].url, accessToken: servers[ 2 ].accessToken, username: user.username, password: user.password })
- const userAccessToken = await userLogin(servers[ 2 ], user)
+ await createUser({ url: servers[2].url, accessToken: servers[2].accessToken, username: user.username, password: user.password })
+ const userAccessToken = await userLogin(servers[2], user)
- const resVideos = await getVideosList(servers[ 2 ].url)
+ const resVideos = await getVideosList(servers[2].url)
video4 = resVideos.body.data.find(v => v.name === 'server3-4')
{
- await rateVideo(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, 'like')
- await rateVideo(servers[ 2 ].url, userAccessToken, video4.id, 'dislike')
+ await rateVideo(servers[2].url, servers[2].accessToken, video4.id, 'like')
+ await rateVideo(servers[2].url, userAccessToken, video4.id, 'dislike')
}
{
{
const text = 'my super first comment'
- const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text)
+ const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text)
const threadId = res.body.comment.id
const text1 = 'my super answer to thread 1'
- const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1)
+ const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1)
const childCommentId = childCommentRes.body.comment.id
const text2 = 'my super answer to answer of thread 1'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text2)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text2)
const text3 = 'my second answer to thread 1'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text3)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text3)
}
{
const text = 'will be deleted'
- const res = await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, text)
+ const res = await addVideoCommentThread(servers[2].url, servers[2].accessToken, video4.id, text)
const threadId = res.body.comment.id
const text1 = 'answer to deleted'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text1)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text1)
const text2 = 'will also be deleted'
- const childCommentRes = await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId, text2)
+ const childCommentRes = await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, threadId, text2)
const childCommentId = childCommentRes.body.comment.id
const text3 = 'my second answer to deleted'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId, text3)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, video4.id, childCommentId, text3)
- await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, threadId)
- await deleteVideoComment(servers[ 2 ].url, servers[ 2 ].accessToken, video4.id, childCommentId)
+ await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, threadId)
+ await deleteVideoComment(servers[2].url, servers[2].accessToken, video4.id, childCommentId)
}
}
await waitJobs(servers)
// Server 1 follows server 3
- await follow(servers[ 0 ].url, [ servers[ 2 ].url ], servers[ 0 ].accessToken)
+ await follow(servers[0].url, [ servers[2].url ], servers[0].accessToken)
await waitJobs(servers)
})
})
it('Should have propagated videos', async function () {
- const res = await getVideosList(servers[ 0 ].url)
+ const res = await getVideosList(servers[0].url)
expect(res.body.total).to.equal(7)
const video2 = res.body.data.find(v => v.name === 'server3-2')
}
]
}
- await completeVideoCheck(servers[ 0 ].url, video4, checkAttributes)
+ await completeVideoCheck(servers[0].url, video4, checkAttributes)
})
it('Should have propagated comments', async function () {
expect(res1.body.data).to.have.lengthOf(2)
{
- const comment: VideoComment = res1.body.data[ 0 ]
+ const comment: VideoComment = res1.body.data[0]
expect(comment.inReplyToCommentId).to.be.null
expect(comment.text).equal('my super first comment')
expect(comment.videoId).to.equal(video4.id)
expect(comment.id).to.equal(comment.threadId)
expect(comment.account.name).to.equal('root')
- expect(comment.account.host).to.equal('localhost:' + servers[ 2 ].port)
+ expect(comment.account.host).to.equal('localhost:' + servers[2].port)
expect(comment.totalReplies).to.equal(3)
expect(dateIsValid(comment.createdAt as string)).to.be.true
expect(dateIsValid(comment.updatedAt as string)).to.be.true
const threadId = comment.threadId
- const res2 = await getVideoThreadComments(servers[ 0 ].url, video4.id, threadId)
+ const res2 = await getVideoThreadComments(servers[0].url, video4.id, threadId)
const tree: VideoCommentThreadTree = res2.body
expect(tree.comment.text).equal('my super first comment')
expect(tree.children).to.have.lengthOf(2)
- const firstChild = tree.children[ 0 ]
+ const firstChild = tree.children[0]
expect(firstChild.comment.text).to.equal('my super answer to thread 1')
expect(firstChild.children).to.have.lengthOf(1)
- const childOfFirstChild = firstChild.children[ 0 ]
+ const childOfFirstChild = firstChild.children[0]
expect(childOfFirstChild.comment.text).to.equal('my super answer to answer of thread 1')
expect(childOfFirstChild.children).to.have.lengthOf(0)
- const secondChild = tree.children[ 1 ]
+ const secondChild = tree.children[1]
expect(secondChild.comment.text).to.equal('my second answer to thread 1')
expect(secondChild.children).to.have.lengthOf(0)
}
await waitJobs(servers)
- let res = await getVideosList(servers[ 0 ].url)
+ const res = await getVideosList(servers[0].url)
expect(res.body.total).to.equal(1)
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import {
cleanupTests,
+ closeAllSequelize,
completeVideoCheck,
flushAndRunMultipleServers,
getVideo,
reRunServer,
ServerInfo,
setAccessTokensToServers,
+ setActorFollowScores,
unfollow,
updateVideo,
- uploadVideo, uploadVideoAndGetId,
- wait,
- setActorFollowScores, closeAllSequelize
+ uploadVideo,
+ uploadVideoAndGetId,
+ wait
} from '../../../../shared/extra-utils'
import { follow, getFollowersListPaginationAndSort } from '../../../../shared/extra-utils/server/follows'
import { getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
let missedVideo2: Video
let unlistedVideo: Video
- let videoIdsServer1: number[] = []
+ const videoIdsServer1: number[] = []
const videoAttributes = {
name: 'my super name for server 1',
// Remove server 2 follower
for (let i = 0; i < 10; i++) {
- await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
+ await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
}
await waitJobs(servers[0])
// Kill server 3
killallServers([ servers[2] ])
- const resLastVideo1 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
+ const resLastVideo1 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
missedVideo1 = resLastVideo1.body.video
- const resLastVideo2 = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
+ const resLastVideo2 = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
missedVideo2 = resLastVideo2.body.video
// Unlisted video
- let resVideo = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, unlistedVideoAttributes)
+ const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, unlistedVideoAttributes)
unlistedVideo = resVideo.body.video
// Add comments to video 2
await wait(11000)
// Only server 3 is still a follower of server 1
- const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(1)
expect(res.body.data[0].follower.host).to.equal('localhost:' + servers[2].port)
for (const state of states) {
const res = await getJobsListPaginationAndSort({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
state: state,
start: 0,
count: 50,
await waitJobs(servers)
- const res = await getFollowersListPaginationAndSort({ url: servers[ 0 ].url, start: 0, count: 2, sort: 'createdAt' })
+ const res = await getFollowersListPaginationAndSort({ url: servers[0].url, start: 0, count: 2, sort: 'createdAt' })
expect(res.body.data).to.be.an('array')
expect(res.body.data).to.have.lengthOf(2)
})
expect(res1.body.data).to.be.an('array')
expect(res1.body.data).to.have.lengthOf(11)
- await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, { })
- await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, { })
+ await updateVideo(servers[0].url, servers[0].accessToken, missedVideo1.uuid, {})
+ await updateVideo(servers[0].url, servers[0].accessToken, unlistedVideo.uuid, {})
await waitJobs(servers)
this.timeout(120000)
for (let i = 0; i < 10; i++) {
- const uuid = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'video ' + i })).uuid
+ const uuid = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video ' + i })).uuid
videoIdsServer1.push(uuid)
}
await waitJobs(servers)
for (const id of videoIdsServer1) {
- await getVideo(servers[ 1 ].url, id)
+ await getVideo(servers[1].url, id)
}
await waitJobs(servers)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-import { cleanupTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { cleanupTests, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
import { doubleFollow } from '../../../../shared/extra-utils/server/follows'
import { getJobsList, getJobsListPaginationAndSort, waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { flushAndRunMultipleServers } from '../../../../shared/extra-utils/server/servers'
it('Should list jobs with sort, pagination and job type', async function () {
{
const res = await getJobsListPaginationAndSort({
- url: servers[ 1 ].url,
- accessToken: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ accessToken: servers[1].accessToken,
state: 'completed',
start: 1,
count: 2,
expect(res.body.total).to.be.above(2)
expect(res.body.data).to.have.lengthOf(2)
- let job: Job = res.body.data[ 0 ]
+ let job: Job = res.body.data[0]
// Skip repeat jobs
- if (job.type === 'videos-views') job = res.body.data[ 1 ]
+ if (job.type === 'videos-views') job = res.body.data[1]
expect(job.state).to.equal('completed')
expect(job.type.startsWith('activitypub-')).to.be.true
{
const res = await getJobsListPaginationAndSort({
- url: servers[ 1 ].url,
- accessToken: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ accessToken: servers[1].accessToken,
state: 'completed',
start: 0,
count: 100,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
before(async function () {
this.timeout(30000)
- server = await flushAndRunServer(1, {}, ['--no-client'])
+ server = await flushAndRunServer(1, {}, [ '--no-client' ])
})
it('Should fail getting the client', function () {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
cleanupTests,
closeAllSequelize,
flushAndRunServer,
- getConfig, getMyUserInformation, getPluginPackageJSON,
+ getConfig,
+ getMyUserInformation,
getPlugin,
+ getPluginPackageJSON,
getPluginRegisteredSettings,
getPluginsCSS,
- installPlugin, killallServers,
+ getPublicSettings,
+ installPlugin,
+ killallServers,
listAvailablePlugins,
- listPlugins, reRunServer,
+ listPlugins,
+ reRunServer,
ServerInfo,
setAccessTokensToServers,
- setPluginVersion, uninstallPlugin,
- updateCustomSubConfig, updateMyUser, updatePluginPackageJSON, updatePlugin,
+ setPluginVersion,
+ uninstallPlugin,
+ updateCustomSubConfig,
+ updateMyUser,
+ updatePlugin,
+ updatePluginPackageJSON,
updatePluginSettings,
- wait, getPublicSettings
+ wait
} from '../../../../shared/extra-utils'
import { PluginType } from '../../../../shared/models/plugins/plugin.type'
import { PeerTubePluginIndex } from '../../../../shared/models/plugins/peertube-plugin-index.model'
expect(res2.body.total).to.be.at.least(2)
expect(data2).to.have.lengthOf(2)
- expect(data1[0].npmName).to.not.equal(data2[ 0 ].npmName)
+ expect(data1[0].npmName).to.not.equal(data2[0].npmName)
}
{
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
doubleFollow,
flushAndRunMultipleServers,
follow,
- killallServers,
ServerInfo,
uploadVideo,
viewVideo,
wait
} from '../../../../shared/extra-utils'
-import { flushTests, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { setAccessTokensToServers } from '../../../../shared/extra-utils/index'
import { getStats } from '../../../../shared/extra-utils/server/stats'
import { addVideoCommentThread } from '../../../../shared/extra-utils/videos/video-comments'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
username: 'user1',
password: 'super_password'
}
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
const resVideo = await uploadVideo(servers[0].url, servers[0].accessToken, { fixture: 'video_short.webm' })
const videoUUID = resVideo.body.video.uuid
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await,@typescript-eslint/no-floating-promises */
import * as magnetUtil from 'magnet-uri'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-import { AccountBlock, ServerBlock, UserNotificationType, Video } from '../../../../shared/index'
+import { AccountBlock, ServerBlock, Video } from '../../../../shared/index'
import {
cleanupTests,
- createUser, deleteVideoComment,
+ createUser,
+ deleteVideoComment,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
- killallServers,
ServerInfo,
uploadVideo,
userLogin
} from '../../../../shared/extra-utils/index'
import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
-import { getVideosListWithToken, getVideosList } from '../../../../shared/extra-utils/videos/videos'
+import { getVideosList, getVideosListWithToken } from '../../../../shared/extra-utils/videos/videos'
import {
addVideoCommentReply,
addVideoCommentThread,
const resComment = await addVideoCommentThread(comment.server.url, comment.token, comment.videoUUID, comment.text)
const threadId = resComment.body.comment.id
- await waitJobs([ mainServer, comment.server])
+ await waitJobs([ mainServer, comment.server ])
const res = await getUserNotifications(mainServer.url, mainServer.accessToken, 0, 30)
const commentNotifications = res.body.data
await deleteVideoComment(comment.server.url, comment.token, comment.videoUUID, threadId)
- await waitJobs([ mainServer, comment.server])
+ await waitJobs([ mainServer, comment.server ])
}
describe('Test blocklist', function () {
{
const user = { username: 'user1', password: 'password' }
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
userToken1 = await userLogin(servers[0], user)
await uploadVideo(servers[0].url, userToken1, { name: 'video user 1' })
{
const user = { username: 'moderator', password: 'password' }
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
userModeratorToken = await userLogin(servers[0], user)
}
{
const user = { username: 'user2', password: 'password' }
- await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
userToken2 = await userLogin(servers[1], user)
await uploadVideo(servers[1].url, userToken2, { name: 'video user 2' })
await doubleFollow(servers[0], servers[1])
{
- const resComment = await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, 'comment root 1')
- const resReply = await addVideoCommentReply(servers[ 0 ].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1')
- await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1')
+ const resComment = await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID1, 'comment root 1')
+ const resReply = await addVideoCommentReply(servers[0].url, userToken1, videoUUID1, resComment.body.comment.id, 'comment user 1')
+ await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resReply.body.comment.id, 'comment root 1')
}
{
- const resComment = await addVideoCommentThread(servers[ 0 ].url, userToken1, videoUUID1, 'comment user 1')
- await addVideoCommentReply(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1')
+ const resComment = await addVideoCommentThread(servers[0].url, userToken1, videoUUID1, 'comment user 1')
+ await addVideoCommentReply(servers[0].url, servers[0].accessToken, videoUUID1, resComment.body.comment.id, 'comment root 1')
}
await waitJobs(servers)
describe('When managing account blocklist', function () {
it('Should list all videos', function () {
- return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken)
+ return checkAllVideos(servers[0].url, servers[0].accessToken)
})
it('Should list the comments', function () {
- return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
})
it('Should block a remote account', async function () {
- await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
+ await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
- const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(3)
})
it('Should block a local account', async function () {
- await addAccountToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1')
+ await addAccountToAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
})
it('Should hide its videos', async function () {
- const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(2)
})
it('Should hide its comments', async function () {
- const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', servers[ 0 ].accessToken)
+ const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', servers[0].accessToken)
const threads: VideoComment[] = resThreads.body.data
expect(threads).to.have.lengthOf(1)
- expect(threads[ 0 ].totalReplies).to.equal(0)
+ expect(threads[0].totalReplies).to.equal(0)
const t = threads.find(t => t.text === 'comment user 1')
expect(t).to.be.undefined
for (const thread of threads) {
- const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, servers[ 0 ].accessToken)
+ const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, servers[0].accessToken)
const tree: VideoCommentThreadTree = res.body
expect(tree.children).to.have.lengthOf(0)
this.timeout(20000)
{
- const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
+ await checkCommentNotification(servers[0], comment, 'absence')
}
{
const comment = {
- server: servers[ 0 ],
+ server: servers[0],
token: userToken1,
videoUUID: videoUUID2,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ await checkCommentNotification(servers[0], comment, 'absence')
}
})
it('Should list all the videos with another user', async function () {
- return checkAllVideos(servers[ 0 ].url, userToken1)
+ return checkAllVideos(servers[0].url, userToken1)
})
it('Should list all the comments with another user', async function () {
- return checkAllComments(servers[ 0 ].url, userToken1, videoUUID1)
+ return checkAllComments(servers[0].url, userToken1, videoUUID1)
})
it('Should list blocked accounts', async function () {
{
- const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt')
+ const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
const blocks: AccountBlock[] = res.body.data
expect(res.body.total).to.equal(2)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('root')
expect(block.byAccount.name).to.equal('root')
expect(block.blockedAccount.displayName).to.equal('user2')
}
{
- const res = await getAccountBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt')
+ const res = await getAccountBlocklistByAccount(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt')
const blocks: AccountBlock[] = res.body.data
expect(res.body.total).to.equal(2)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('root')
expect(block.byAccount.name).to.equal('root')
expect(block.blockedAccount.displayName).to.equal('user1')
})
it('Should unblock the remote account', async function () {
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
+ await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should display its videos', async function () {
- const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(3)
})
it('Should unblock the local account', async function () {
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1')
+ await removeAccountFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'user1')
})
it('Should display its comments', function () {
- return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
})
it('Should have a notification from a non blocked account', async function () {
this.timeout(20000)
{
- const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
+ await checkCommentNotification(servers[0], comment, 'presence')
}
{
const comment = {
- server: servers[ 0 ],
+ server: servers[0],
token: userToken1,
videoUUID: videoUUID2,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ await checkCommentNotification(servers[0], comment, 'presence')
}
})
})
describe('When managing server blocklist', function () {
it('Should list all videos', function () {
- return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken)
+ return checkAllVideos(servers[0].url, servers[0].accessToken)
})
it('Should list the comments', function () {
- return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
})
it('Should block a remote server', async function () {
- await addServerToAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await addServerToAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
- const res = await getVideosListWithToken(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideosListWithToken(servers[0].url, servers[0].accessToken)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(2)
})
it('Should list all the videos with another user', async function () {
- return checkAllVideos(servers[ 0 ].url, userToken1)
+ return checkAllVideos(servers[0].url, userToken1)
})
it('Should hide its comments', async function () {
this.timeout(10000)
- const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2')
+ const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2')
const threadId = resThreads.body.comment.id
await waitJobs(servers)
- await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
- await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId)
+ await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId)
})
it('Should not have notifications from blocked server', async function () {
this.timeout(20000)
{
- const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
+ await checkCommentNotification(servers[0], comment, 'absence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ await checkCommentNotification(servers[0], comment, 'absence')
}
})
it('Should list blocked servers', async function () {
- const res = await getServerBlocklistByAccount(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt')
+ const res = await getServerBlocklistByAccount(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
const blocks: ServerBlock[] = res.body.data
expect(res.body.total).to.equal(1)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('root')
expect(block.byAccount.name).to.equal('root')
expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
})
it('Should unblock the remote server', async function () {
- await removeServerFromAccountBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await removeServerFromAccountBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
})
it('Should display its videos', function () {
- return checkAllVideos(servers[ 0 ].url, servers[ 0 ].accessToken)
+ return checkAllVideos(servers[0].url, servers[0].accessToken)
})
it('Should display its comments', function () {
- return checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ return checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
})
it('Should have notification from unblocked server', async function () {
this.timeout(20000)
{
- const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
+ await checkCommentNotification(servers[0], comment, 'presence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ await checkCommentNotification(servers[0], comment, 'presence')
}
})
})
describe('When managing account blocklist', function () {
it('Should list all videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllVideos(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllVideos(servers[0].url, token)
}
})
it('Should list the comments', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllComments(servers[ 0 ].url, token, videoUUID1)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllComments(servers[0].url, token, videoUUID1)
}
})
it('Should block a remote account', async function () {
- await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
+ await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- const res = await getVideosListWithToken(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ const res = await getVideosListWithToken(servers[0].url, token)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(3)
})
it('Should block a local account', async function () {
- await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1')
+ await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'user1')
})
it('Should hide its videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- const res = await getVideosListWithToken(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ const res = await getVideosListWithToken(servers[0].url, token)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(2)
})
it('Should hide its comments', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- const resThreads = await getVideoCommentThreads(servers[ 0 ].url, videoUUID1, 0, 5, '-createdAt', token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ const resThreads = await getVideoCommentThreads(servers[0].url, videoUUID1, 0, 5, '-createdAt', token)
const threads: VideoComment[] = resThreads.body.data
expect(threads).to.have.lengthOf(1)
- expect(threads[ 0 ].totalReplies).to.equal(0)
+ expect(threads[0].totalReplies).to.equal(0)
const t = threads.find(t => t.text === 'comment user 1')
expect(t).to.be.undefined
for (const thread of threads) {
- const res = await getVideoThreadComments(servers[ 0 ].url, videoUUID1, thread.id, token)
+ const res = await getVideoThreadComments(servers[0].url, videoUUID1, thread.id, token)
const tree: VideoCommentThreadTree = res.body
expect(tree.children).to.have.lengthOf(0)
this.timeout(20000)
{
- const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'hidden comment' }
+ await checkCommentNotification(servers[0], comment, 'absence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ await checkCommentNotification(servers[0], comment, 'absence')
}
})
it('Should list blocked accounts', async function () {
{
- const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt')
+ const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
const blocks: AccountBlock[] = res.body.data
expect(res.body.total).to.equal(2)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('peertube')
expect(block.byAccount.name).to.equal('peertube')
expect(block.blockedAccount.displayName).to.equal('user2')
}
{
- const res = await getAccountBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 1, 2, 'createdAt')
+ const res = await getAccountBlocklistByServer(servers[0].url, servers[0].accessToken, 1, 2, 'createdAt')
const blocks: AccountBlock[] = res.body.data
expect(res.body.total).to.equal(2)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('peertube')
expect(block.byAccount.name).to.equal('peertube')
expect(block.blockedAccount.displayName).to.equal('user1')
})
it('Should unblock the remote account', async function () {
- await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user2@localhost:' + servers[1].port)
+ await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user2@localhost:' + servers[1].port)
})
it('Should display its videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- const res = await getVideosListWithToken(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ const res = await getVideosListWithToken(servers[0].url, token)
const videos: Video[] = res.body.data
expect(videos).to.have.lengthOf(3)
})
it('Should unblock the local account', async function () {
- await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'user1')
+ await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'user1')
})
it('Should display its comments', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllComments(servers[ 0 ].url, token, videoUUID1)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllComments(servers[0].url, token, videoUUID1)
}
})
this.timeout(20000)
{
- const comment = { server: servers[ 0 ], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ const comment = { server: servers[0], token: userToken1, videoUUID: videoUUID1, text: 'displayed comment' }
+ await checkCommentNotification(servers[0], comment, 'presence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ await checkCommentNotification(servers[0], comment, 'presence')
}
})
})
describe('When managing server blocklist', function () {
it('Should list all videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllVideos(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllVideos(servers[0].url, token)
}
})
it('Should list the comments', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllComments(servers[ 0 ].url, token, videoUUID1)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllComments(servers[0].url, token, videoUUID1)
}
})
it('Should block a remote server', async function () {
- await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
})
it('Should hide its videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- const res1 = await getVideosList(servers[ 0 ].url)
- const res2 = await getVideosListWithToken(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ const res1 = await getVideosList(servers[0].url)
+ const res2 = await getVideosListWithToken(servers[0].url, token)
for (const res of [ res1, res2 ]) {
const videos: Video[] = res.body.data
it('Should hide its comments', async function () {
this.timeout(10000)
- const resThreads = await addVideoCommentThread(servers[ 1 ].url, userToken2, videoUUID1, 'hidden comment 2')
+ const resThreads = await addVideoCommentThread(servers[1].url, userToken2, videoUUID1, 'hidden comment 2')
const threadId = resThreads.body.comment.id
await waitJobs(servers)
- await checkAllComments(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID1)
+ await checkAllComments(servers[0].url, servers[0].accessToken, videoUUID1)
- await deleteVideoComment(servers[ 1 ].url, userToken2, videoUUID1, threadId)
+ await deleteVideoComment(servers[1].url, userToken2, videoUUID1, threadId)
})
it('Should not have notification from blocked instances by instance', async function () {
this.timeout(20000)
{
- const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'hidden comment' }
+ await checkCommentNotification(servers[0], comment, 'absence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'absence')
+ await checkCommentNotification(servers[0], comment, 'absence')
}
})
it('Should list blocked servers', async function () {
- const res = await getServerBlocklistByServer(servers[ 0 ].url, servers[ 0 ].accessToken, 0, 1, 'createdAt')
+ const res = await getServerBlocklistByServer(servers[0].url, servers[0].accessToken, 0, 1, 'createdAt')
const blocks: ServerBlock[] = res.body.data
expect(res.body.total).to.equal(1)
- const block = blocks[ 0 ]
+ const block = blocks[0]
expect(block.byAccount.displayName).to.equal('peertube')
expect(block.byAccount.name).to.equal('peertube')
expect(block.blockedServer.host).to.equal('localhost:' + servers[1].port)
})
it('Should unblock the remote server', async function () {
- await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
})
it('Should list all videos', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllVideos(servers[ 0 ].url, token)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllVideos(servers[0].url, token)
}
})
it('Should list the comments', async function () {
- for (const token of [ userModeratorToken, servers[ 0 ].accessToken ]) {
- await checkAllComments(servers[ 0 ].url, token, videoUUID1)
+ for (const token of [ userModeratorToken, servers[0].accessToken ]) {
+ await checkAllComments(servers[0].url, token, videoUUID1)
}
})
this.timeout(20000)
{
- const comment = { server: servers[ 1 ], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ const comment = { server: servers[1], token: userToken2, videoUUID: videoUUID1, text: 'displayed comment' }
+ await checkCommentNotification(servers[0], comment, 'presence')
}
{
const comment = {
- server: servers[ 1 ],
+ server: servers[1],
token: userToken2,
videoUUID: videoUUID1,
- text: 'hello @root@localhost:' + servers[ 0 ].port
+ text: 'hello @root@localhost:' + servers[0].port
}
- await checkCommentNotification(servers[ 0 ], comment, 'presence')
+ await checkCommentNotification(servers[0], comment, 'presence')
}
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
updateVideo,
userLogin
} from '../../../../shared/extra-utils'
-import { killallServers, ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
+import { ServerInfo, uploadVideo } from '../../../../shared/extra-utils/index'
import { setAccessTokensToServers } from '../../../../shared/extra-utils/users/login'
import { Video, VideoChannel } from '../../../../shared/models/videos'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import {
addUserSubscription,
+ areSubscriptionsExist,
+ getUserSubscription,
listUserSubscriptions,
listUserSubscriptionVideos,
- removeUserSubscription,
- getUserSubscription, areSubscriptionsExist
+ removeUserSubscription
} from '../../../../shared/extra-utils/users/user-subscriptions'
const expect = chai.expect
it('Should get subscription', async function () {
{
- const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'user3_channel@localhost:' + servers[2].port)
+ const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'user3_channel@localhost:' + servers[2].port)
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('user3_channel')
}
{
- const res = await getUserSubscription(servers[ 0 ].url, users[ 0 ].accessToken, 'root_channel@localhost:' + servers[0].port)
+ const res = await getUserSubscription(servers[0].url, users[0].accessToken, 'root_channel@localhost:' + servers[0].port)
const videoChannel: VideoChannel = res.body
expect(videoChannel.name).to.equal('root_channel')
'user3_channel@localhost:' + servers[0].port
]
- const res = await areSubscriptionsExist(servers[ 0 ].url, users[ 0 ].accessToken, uris)
+ const res = await areSubscriptionsExist(servers[0].url, users[0].accessToken, uris)
const body = res.body
expect(body['user3_channel@localhost:' + servers[2].port]).to.be.true
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
password: 'password'
}
const res = await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: user.username,
password: user.password
})
userId = res.body.user.id
- userAccessToken = await userLogin(servers[ 0 ], user)
+ userAccessToken = await userLogin(servers[0], user)
}
{
- const resVideo = await uploadVideo(servers[ 0 ].url, userAccessToken, {})
+ const resVideo = await uploadVideo(servers[0].url, userAccessToken, {})
videoUUID = resVideo.body.video.uuid
}
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
user = res.body
- const account: Account = user.account
expect(user.account.displayName).to.equal('my super display name')
await waitJobs(servers)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-import { User, UserRole, Video, MyUser, VideoPlaylistType } from '../../../../shared/index'
+import { MyUser, User, UserRole, Video, VideoPlaylistType } from '../../../../shared/index'
import {
blockUser,
cleanupTests,
getUsersList,
getUsersListPaginationAndSort,
getVideoChannel,
- getVideosList, installPlugin,
+ getVideosList,
+ installPlugin,
login,
makePutBodyRequest,
rateVideo,
it('Should be able to login with an insensitive username', async function () {
const user = { username: 'RoOt', password: server.user.password }
- const res = await login(server.url, server.client, user, 200)
+ await login(server.url, server.client, user, 200)
const user2 = { username: 'rOoT', password: server.user.password }
- const res2 = await login(server.url, server.client, user2, 200)
+ await login(server.url, server.client, user2, 200)
const user3 = { username: 'ROOt', password: server.user.password }
- const res3 = await login(server.url, server.client, user3, 200)
+ await login(server.url, server.client, user3, 200)
})
})
const videoAttributes = {}
await uploadVideo(server.url, accessToken, videoAttributes)
const res = await getVideosList(server.url)
- const video = res.body.data[ 0 ]
+ const video = res.body.data[0]
expect(video.account.name).to.equal('root')
videoId = video.id
const ratings = res.body
expect(ratings.total).to.equal(1)
- expect(ratings.data[ 0 ].video.id).to.equal(videoId)
- expect(ratings.data[ 0 ].rating).to.equal('like')
+ expect(ratings.data[0].video.id).to.equal(videoId)
+ expect(ratings.data[0].rating).to.equal('like')
})
it('Should retrieve ratings list by rating type', async function () {
const videos = res.body.data
expect(videos).to.have.lengthOf(1)
- const video: Video = videos[ 0 ]
+ const video: Video = videos[0]
expect(video.name).to.equal('super user video')
expect(video.thumbnailPath).to.not.be.null
expect(video.previewPath).to.not.be.null
expect(users).to.be.an('array')
expect(users.length).to.equal(2)
- const user = users[ 0 ]
+ const user = users[0]
expect(user.username).to.equal('user_1')
expect(user.email).to.equal('user_1@example.com')
expect(user.nsfwPolicy).to.equal('display')
- const rootUser = users[ 1 ]
+ const rootUser = users[1]
expect(rootUser.username).to.equal('root')
expect(rootUser.email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(user.nsfwPolicy).to.equal('display')
expect(total).to.equal(2)
expect(users.length).to.equal(1)
- const user = users[ 0 ]
+ const user = users[0]
expect(user.username).to.equal('root')
expect(user.email).to.equal('admin' + server.internalServerNumber + '@example.com')
expect(user.roleLabel).to.equal('Administrator')
expect(total).to.equal(2)
expect(users.length).to.equal(1)
- const user = users[ 0 ]
+ const user = users[0]
expect(user.username).to.equal('user_1')
expect(user.email).to.equal('user_1@example.com')
expect(user.nsfwPolicy).to.equal('display')
expect(total).to.equal(2)
expect(users.length).to.equal(1)
- const user = users[ 0 ]
+ const user = users[0]
expect(user.username).to.equal('user_1')
expect(user.email).to.equal('user_1@example.com')
expect(user.nsfwPolicy).to.equal('display')
expect(total).to.equal(2)
expect(users.length).to.equal(2)
- expect(users[ 0 ].username).to.equal('root')
- expect(users[ 0 ].email).to.equal('admin' + server.internalServerNumber + '@example.com')
- expect(users[ 0 ].nsfwPolicy).to.equal('display')
+ expect(users[0].username).to.equal('root')
+ expect(users[0].email).to.equal('admin' + server.internalServerNumber + '@example.com')
+ expect(users[0].nsfwPolicy).to.equal('display')
- expect(users[ 1 ].username).to.equal('user_1')
- expect(users[ 1 ].email).to.equal('user_1@example.com')
- expect(users[ 1 ].nsfwPolicy).to.equal('display')
+ expect(users[1].username).to.equal('user_1')
+ expect(users[1].email).to.equal('user_1@example.com')
+ expect(users[1].nsfwPolicy).to.equal('display')
})
it('Should search user by username', async function () {
expect(res.body.total).to.equal(1)
expect(users.length).to.equal(1)
- expect(users[ 0 ].username).to.equal('root')
+ expect(users[0].username).to.equal('root')
})
it('Should search user by email', async function () {
expect(res.body.total).to.equal(1)
expect(users.length).to.equal(1)
- expect(users[ 0 ].username).to.equal('user_1')
- expect(users[ 0 ].email).to.equal('user_1@example.com')
+ expect(users[0].username).to.equal('user_1')
+ expect(users[0].email).to.equal('user_1@example.com')
}
{
expect(res.body.total).to.equal(2)
expect(users.length).to.equal(2)
- expect(users[ 0 ].username).to.equal('root')
- expect(users[ 1 ].username).to.equal('user_1')
+ expect(users[0].username).to.equal('root')
+ expect(users[1].username).to.equal('user_1')
}
})
})
expect(res.body.total).to.equal(1)
- const video = res.body.data[ 0 ]
+ const video = res.body.data[0]
expect(video.account.name).to.equal('root')
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import {
- checkDirectoryIsEmpty,
- checkSegmentHash,
- checkTmpIsEmpty,
cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
- getPlaylist,
- getVideo, makeGetRequest, makeRawRequest,
- removeVideo, root,
+ getVideo,
+ root,
ServerInfo,
- setAccessTokensToServers, updateCustomSubConfig,
- updateVideo,
+ setAccessTokensToServers,
uploadVideo,
- waitJobs, webtorrentAdd
+ waitJobs
} from '../../../../shared/extra-utils'
import { VideoDetails } from '../../../../shared/models/videos'
-import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
import { join } from 'path'
-import { DEFAULT_AUDIO_RESOLUTION } from '../../../initializers/constants'
-import { getVideoFileBitrate, getVideoFileFPS, getVideoFileResolution, audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils'
+import { audio, getVideoStreamSize } from '@server/helpers/ffmpeg-utils'
const expect = chai.expect
it('0p transcoded video should not have video', async function () {
const paths = [
- join(root(), 'test' + servers[ 0 ].internalServerNumber, 'videos', videoUUID + '-0.mp4'),
- join(root(), 'test' + servers[ 0 ].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4')
+ join(root(), 'test' + servers[0].internalServerNumber, 'videos', videoUUID + '-0.mp4'),
+ join(root(), 'test' + servers[0].internalServerNumber, 'streaming-playlists', 'hls', videoUUID, videoUUID + '-0-fragmented.mp4')
]
for (const path of paths) {
const { audioStream } = await audio.get(path)
- expect(audioStream[ 'codec_name' ]).to.be.equal('aac')
- expect(audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000)
+ expect(audioStream['codec_name']).to.be.equal('aac')
+ expect(audioStream['bit_rate']).to.be.at.most(384 * 8000)
const size = await getVideoStreamSize(path)
expect(size.height).to.equal(0)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
displayName: 'my channel',
description: 'super channel'
}
- await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel)
- const channelRes = await getVideoChannelsList(servers[ 0 ].url, 0, 1)
- videoChannelId = channelRes.body.data[ 0 ].id
+ await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
+ const channelRes = await getVideoChannelsList(servers[0].url, 0, 1)
+ videoChannelId = channelRes.body.data[0].id
}
// Server 1 and server 2 follow each other
username: 'user1',
password: 'super_password'
}
- await createUser({ url: servers[ 1 ].url, accessToken: servers[ 1 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[1].url, accessToken: servers[1].accessToken, username: user.username, password: user.password })
const userAccessToken = await userLogin(servers[1], user)
const videoAttributes = {
{
const text = 'my super first comment'
- await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, text)
+ await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoUUID, text)
}
{
const text = 'my super second comment'
- await addVideoCommentThread(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, text)
+ await addVideoCommentThread(servers[2].url, servers[2].accessToken, videoUUID, text)
}
await waitJobs(servers)
const threadId = res.body.data.find(c => c.text === 'my super first comment').id
const text = 'my super answer to thread 1'
- await addVideoCommentReply(servers[ 1 ].url, servers[ 1 ].accessToken, videoUUID, threadId, text)
+ await addVideoCommentReply(servers[1].url, servers[1].accessToken, videoUUID, threadId, text)
}
await waitJobs(servers)
const childCommentId = res2.body.children[0].comment.id
const text3 = 'my second answer to thread 1'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, threadId, text3)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, threadId, text3)
const text2 = 'my super answer to answer of thread 1'
- await addVideoCommentReply(servers[ 2 ].url, servers[ 2 ].accessToken, videoUUID, childCommentId, text2)
+ await addVideoCommentReply(servers[2].url, servers[2].accessToken, videoUUID, childCommentId, text2)
}
await waitJobs(servers)
it('Should delete the thread comments', async function () {
this.timeout(10000)
- const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5)
+ const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
const threadId = res.body.data.find(c => c.text === 'my super first comment').id
- await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId)
+ await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
await waitJobs(servers)
})
it('Should delete a remote thread by the origin server', async function () {
this.timeout(5000)
- const res = await getVideoCommentThreads(servers[ 0 ].url, videoUUID, 0, 5)
+ const res = await getVideoCommentThreads(servers[0].url, videoUUID, 0, 5)
const threadId = res.body.data.find(c => c.text === 'my super second comment').id
- await deleteVideoComment(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, threadId)
+ await deleteVideoComment(servers[0].url, servers[0].accessToken, videoUUID, threadId)
await waitJobs(servers)
})
const filePath = join(__dirname, '..', '..', 'fixtures', 'video_short.webm')
await req.attach('videofile', filePath)
- .expect(200)
+ .expect(200)
await waitJobs(servers)
duration: 5,
commentsEnabled: true,
downloadEnabled: true,
- tags: [ ],
+ tags: [],
privacy: VideoPrivacy.PUBLIC,
channel: {
displayName: 'Main root channel',
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
const res = await getOEmbed(server.url, oembedUrl)
const expectedHtml = '<iframe width="560" height="315" sandbox="allow-same-origin allow-scripts" ' +
- `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
- 'frameborder="0" allowfullscreen></iframe>'
+ `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
+ 'frameborder="0" allowfullscreen></iframe>'
const expectedThumbnailUrl = 'http://localhost:' + server.port + '/static/previews/' + server.video.uuid + '.jpg'
expect(res.body.html).to.equal(expectedHtml)
const res = await getOEmbed(server.url, oembedUrl, format, maxHeight, maxWidth)
const expectedHtml = '<iframe width="50" height="50" sandbox="allow-same-origin allow-scripts" ' +
- `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
- 'frameborder="0" allowfullscreen></iframe>'
+ `src="http://localhost:${server.port}/videos/embed/${server.video.uuid}" ` +
+ 'frameborder="0" allowfullscreen></iframe>'
expect(res.body.html).to.equal(expectedHtml)
expect(res.body.title).to.equal(server.video.name)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import { keyBy } from 'lodash'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
const accountToBlock = 'root@localhost:' + servers[1].port
{
- await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock)
+ await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
- const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
expect(res.body.total).to.equal(2)
const abuse = res.body.data.find(a => a.reason === 'will mute this')
}
{
- await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, accountToBlock)
+ await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, accountToBlock)
- const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
expect(res.body.total).to.equal(3)
}
})
const serverToBlock = servers[1].host
{
- await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, servers[1].host)
+ await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, servers[1].host)
- const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
expect(res.body.total).to.equal(2)
const abuse = res.body.data.find(a => a.reason === 'will mute this')
}
{
- await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, serverToBlock)
+ await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, serverToBlock)
- const res = await getVideoAbusesList(servers[ 0 ].url, servers[ 0 ].accessToken)
+ const res = await getVideoAbusesList(servers[0].url, servers[0].accessToken)
expect(res.body.total).to.equal(3)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import { orderBy } from 'lodash'
cleanupTests,
createUser,
flushAndRunMultipleServers,
- getBlacklistedVideosList, getMyUserInformation,
+ getBlacklistedVideosList,
+ getMyUserInformation,
getMyVideos,
getVideosList,
killallServers,
searchVideo,
ServerInfo,
setAccessTokensToServers,
- setDefaultVideoChannel,
updateVideo,
updateVideoBlacklist,
uploadVideo,
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import { VideoBlacklist, VideoBlacklistType } from '../../../../shared/models/videos'
import { UserAdminFlag } from '../../../../shared/models/users/user-flag.model'
-import { User, UserRole, UserUpdateMe } from '../../../../shared/models/users'
+import { User, UserRole } from '../../../../shared/models/users'
import { getMagnetURI, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
const expect = chai.expect
const res = await getVideosList(server.url)
const videos = res.body.data
- for (let video of videos) {
+ for (const video of videos) {
await addVideoToBlacklist(server.url, server.accessToken, video.id, 'super reason')
}
}
it('Should not have the video blacklisted in videos list/search on server 1', async function () {
{
- const res = await getVideosList(servers[ 0 ].url)
+ const res = await getVideosList(servers[0].url)
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
}
{
- const res = await searchVideo(servers[ 0 ].url, 'name')
+ const res = await searchVideo(servers[0].url, 'name')
expect(res.body.total).to.equal(0)
expect(res.body.data).to.be.an('array')
it('Should have the blacklisted video in videos list/search on server 2', async function () {
{
- const res = await getVideosList(servers[ 1 ].url)
+ const res = await getVideosList(servers[1].url)
expect(res.body.total).to.equal(2)
expect(res.body.data).to.be.an('array')
}
{
- const res = await searchVideo(servers[ 1 ].url, 'video')
+ const res = await searchVideo(servers[1].url, 'video')
expect(res.body.total).to.equal(2)
expect(res.body.data).to.be.an('array')
it('Should display all the blacklisted videos when applying manual type filter', async function () {
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
type: VideoBlacklistType.MANUAL
})
it('Should display nothing when applying automatic type filter', async function () {
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
})
})
it('Should get the correct sort when sorting by descending id', async function () {
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-id' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-id' })
expect(res.body.total).to.equal(2)
const blacklistedVideos = res.body.data
})
it('Should get the correct sort when sorting by descending video name', async function () {
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
expect(res.body.total).to.equal(2)
const blacklistedVideos = res.body.data
})
it('Should get the correct sort when sorting by ascending creation date', async function () {
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' })
expect(res.body.total).to.equal(2)
const blacklistedVideos = res.body.data
it('Should change the reason', async function () {
await updateVideoBlacklist(servers[0].url, servers[0].accessToken, videoId, 'my super reason updated')
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
const video = res.body.data.find(b => b.video.id === videoId)
expect(video.reason).to.equal('my super reason updated')
it('Should remove a video from the blacklist on server 1', async function () {
// Get one video in the blacklist
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
videoToRemove = res.body.data[0]
blacklist = res.body.data.slice(1)
})
it('Should not have the ex-blacklisted video in videos blacklist list on server 1', async function () {
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: '-name' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: '-name' })
expect(res.body.total).to.equal(1)
const videos = res.body.data
video3UUID = res.body.video.uuid
}
{
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'Video 4' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'Video 4' })
video4UUID = res.body.video.uuid
}
it('Should blacklist video 3 and keep it federated', async function () {
this.timeout(10000)
- await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video3UUID, 'super reason', false)
+ await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video3UUID, 'super reason', false)
await waitJobs(servers)
{
- const res = await getVideosList(servers[ 0 ].url)
+ const res = await getVideosList(servers[0].url)
expect(res.body.data.find(v => v.uuid === video3UUID)).to.be.undefined
}
{
- const res = await getVideosList(servers[ 1 ].url)
+ const res = await getVideosList(servers[1].url)
expect(res.body.data.find(v => v.uuid === video3UUID)).to.not.be.undefined
}
})
it('Should unfederate the video', async function () {
this.timeout(10000)
- await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, 'super reason', true)
+ await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video4UUID, 'super reason', true)
await waitJobs(servers)
it('Should have the video unfederated even after an Update AP message', async function () {
this.timeout(10000)
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID, { description: 'super description' })
+ await updateVideo(servers[0].url, servers[0].accessToken, video4UUID, { description: 'super description' })
await waitJobs(servers)
})
it('Should have the correct video blacklist unfederate attribute', async function () {
- const res = await getBlacklistedVideosList({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, sort: 'createdAt' })
+ const res = await getBlacklistedVideosList({ url: servers[0].url, token: servers[0].accessToken, sort: 'createdAt' })
const blacklistedVideos: VideoBlacklist[] = res.body.data
const video3Blacklisted = blacklistedVideos.find(b => b.video.uuid === video3UUID)
it('Should remove the video from blacklist and refederate the video', async function () {
this.timeout(10000)
- await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video4UUID)
+ await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video4UUID)
await waitJobs(servers)
killallServers([ servers[0] ])
const config = {
- 'auto_blacklist': {
+ auto_blacklist: {
videos: {
- 'of_users': {
+ of_users: {
enabled: true
}
}
{
const user = { username: 'user_without_flag', password: 'password' }
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: user.username,
adminFlags: UserAdminFlag.NONE,
password: user.password,
{
const user = { username: 'user_with_flag', password: 'password' }
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: user.username,
adminFlags: UserAdminFlag.BY_PASS_VIDEO_AUTO_BLACKLIST,
password: user.password,
await uploadVideo(servers[0].url, userWithoutFlag, { name: 'blacklisted' })
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
})
name: 'URL import',
channelId: channelOfUserWithoutFlag
}
- await importVideo(servers[ 0 ].url, userWithoutFlag, attributes)
+ await importVideo(servers[0].url, userWithoutFlag, attributes)
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
sort: 'createdAt',
type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
})
name: 'Torrent import',
channelId: channelOfUserWithoutFlag
}
- await importVideo(servers[ 0 ].url, userWithoutFlag, attributes)
+ await importVideo(servers[0].url, userWithoutFlag, attributes)
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
sort: 'createdAt',
type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
})
await uploadVideo(servers[0].url, userWithFlag, { name: 'not blacklisted' })
const res = await getBlacklistedVideosList({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import {
- checkVideoFilesWereRemoved, cleanupTests,
+ checkVideoFilesWereRemoved,
+ cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
removeVideo,
uploadVideo,
wait
} from '../../../../shared/extra-utils'
-import { flushTests, killallServers, ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
+import { ServerInfo, setAccessTokensToServers } from '../../../../shared/extra-utils/index'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
import {
createVideoCaption,
await waitJobs(servers)
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'my video name' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'my video name' })
videoUUID = res.body.video.uuid
await waitJobs(servers)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
}
let firstUserAccessToken = ''
let secondUserAccessToken = ''
- let lastRequestChangeOwnershipId = undefined
+ let lastRequestChangeOwnershipId = ''
before(async function () {
this.timeout(50000)
const videoQuota = 42000000
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: firstUser.username,
password: firstUser.password,
videoQuota: videoQuota
})
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: secondUser.username,
password: secondUser.password,
videoQuota: videoQuota
})
describe('Test video change ownership - quota too small', function () {
- let server: ServerInfo = undefined
+ let server: ServerInfo
const firstUser = {
username: 'first',
password: 'My great password'
}
let firstUserAccessToken = ''
let secondUserAccessToken = ''
- let lastRequestChangeOwnershipId = undefined
+ let lastRequestChangeOwnershipId = ''
before(async function () {
this.timeout(50000)
// Run one server
server = await flushAndRunServer(1)
- await setAccessTokensToServers([server])
+ await setAccessTokensToServers([ server ])
const videoQuota = 42000000
const limitedVideoQuota = 10
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
cleanupTests,
createUser,
doubleFollow,
- flushAndRunMultipleServers, getVideo,
+ flushAndRunMultipleServers,
+ getVideo,
getVideoChannelVideos,
testImage,
updateVideo,
description: 'super video channel description',
support: 'super video channel support text'
}
- const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel)
+ const res = await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
secondVideoChannelId = res.body.videoChannel.id
}
// The channel is 1 is propagated to servers 2
{
const videoAttributesArg = { name: 'my video name', channelId: secondVideoChannelId, support: 'video support field' }
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributesArg)
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributesArg)
videoUUID = res.body.video.uuid
}
it('Should have two video channels when getting account channels on server 1', async function () {
const res = await getAccountVideoChannelsList({
- url: servers[ 0 ].url,
+ url: servers[0].url,
accountName: userInfo.account.name + '@' + userInfo.account.host
})
it('Should paginate and sort account channels', async function () {
{
const res = await getAccountVideoChannelsList({
- url: servers[ 0 ].url,
+ url: servers[0].url,
accountName: userInfo.account.name + '@' + userInfo.account.host,
start: 0,
count: 1,
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(1)
- const videoChannel: VideoChannel = res.body.data[ 0 ]
+ const videoChannel: VideoChannel = res.body.data[0]
expect(videoChannel.name).to.equal('root_channel')
}
{
const res = await getAccountVideoChannelsList({
- url: servers[ 0 ].url,
+ url: servers[0].url,
accountName: userInfo.account.name + '@' + userInfo.account.host,
start: 0,
count: 1,
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(1)
- const videoChannel: VideoChannel = res.body.data[ 0 ]
+ const videoChannel: VideoChannel = res.body.data[0]
expect(videoChannel.name).to.equal('second_video_channel')
}
{
const res = await getAccountVideoChannelsList({
- url: servers[ 0 ].url,
+ url: servers[0].url,
accountName: userInfo.account.name + '@' + userInfo.account.host,
start: 1,
count: 1,
expect(res.body.total).to.equal(2)
expect(res.body.data).to.have.lengthOf(1)
- const videoChannel: VideoChannel = res.body.data[ 0 ]
+ const videoChannel: VideoChannel = res.body.data[0]
expect(videoChannel.name).to.equal('root_channel')
}
})
it('Should have one video channel when getting account channels on server 2', async function () {
const res = await getAccountVideoChannelsList({
- url: servers[ 1 ].url,
+ url: servers[1].url,
accountName: userInfo.account.name + '@' + userInfo.account.host
})
it('Should create the main channel with an uuid if there is a conflict', async function () {
{
const videoChannel = { name: 'toto_channel', displayName: 'My toto channel' }
- await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, videoChannel)
+ await addVideoChannel(servers[0].url, servers[0].accessToken, videoChannel)
}
{
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: 'toto', password: 'password' })
- const accessToken = await userLogin(servers[ 0 ], { username: 'toto', password: 'password' })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: 'toto', password: 'password' })
+ const accessToken = await userLogin(servers[0], { username: 'toto', password: 'password' })
- const res = await getMyUserInformation(servers[ 0 ].url, accessToken)
- const videoChannel = res.body.videoChannels[ 0 ]
+ const res = await getMyUserInformation(servers[0].url, accessToken)
+ const videoChannel = res.body.videoChannels[0]
expect(videoChannel.name).to.match(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
import { cleanupTests, testImage } from '../../../../shared/extra-utils'
import {
+ createUser,
dateIsValid,
flushAndRunServer,
+ getAccessToken,
ServerInfo,
setAccessTokensToServers,
updateMyAvatar,
- getAccessToken,
- createUser,
uploadVideo
} from '../../../../shared/extra-utils/index'
import {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
getVideo,
getVideoDescription,
getVideosList,
- killallServers,
ServerInfo,
setAccessTokensToServers,
updateVideo,
let servers: ServerInfo[] = []
let videoUUID = ''
let videoId: number
- let longDescription = 'my super description for server 1'.repeat(50)
+ const longDescription = 'my super description for server 1'.repeat(50)
before(async function () {
this.timeout(40000)
// 30 characters * 6 -> 240 characters
const truncatedDescription = 'my super description for server 1'.repeat(7) +
- 'my super descrip...'
+ 'my super descrip...'
expect(video.description).to.equal(truncatedDescription)
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
doubleFollow,
flushAndRunMultipleServers,
getPlaylist,
- getVideo, makeGetRequest, makeRawRequest,
+ getVideo,
+ makeRawRequest,
removeVideo,
ServerInfo,
- setAccessTokensToServers, updateCustomSubConfig,
+ setAccessTokensToServers,
+ updateCustomSubConfig,
updateVideo,
uploadVideo,
- waitJobs, webtorrentAdd
+ waitJobs,
+ webtorrentAdd
} from '../../../../shared/extra-utils'
import { VideoDetails } from '../../../../shared/models/videos'
import { VideoStreamingPlaylistType } from '../../../../shared/models/videos/video-streaming-playlist.type'
expect(file.magnetUri).to.have.lengthOf.above(2)
expect(file.torrentUrl).to.equal(`${baseUrl}/static/torrents/${videoDetails.uuid}-${file.resolution.id}-hls.torrent`)
- expect(file.fileUrl).to.equal(`${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`)
+ expect(file.fileUrl).to.equal(
+ `${baseUrl}/static/streaming-playlists/hls/${videoDetails.uuid}/${videoDetails.uuid}-${file.resolution.id}-fragmented.mp4`
+ )
expect(file.resolution.label).to.equal(resolution + 'p')
await makeRawRequest(file.torrentUrl, 200)
const masterPlaylist = res.text
for (const resolution of resolutions) {
- const reg = new RegExp('#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"')
+ const reg = new RegExp(
+ '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',FRAME-RATE=\\d+,CODECS="avc1.64001f,mp4a.40.2"'
+ )
expect(masterPlaylist).to.match(reg)
expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
it('Should upload a video and transcode it to HLS', async function () {
this.timeout(120000)
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video 1', fixture: 'video_short.webm' })
videoUUID = res.body.video.uuid
await waitJobs(servers)
it('Should upload an audio file and transcode it to HLS', async function () {
this.timeout(120000)
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video audio', fixture: 'sample.ogg' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video audio', fixture: 'sample.ogg' })
videoAudioUUID = res.body.video.uuid
await waitJobs(servers)
it('Should update the video', async function () {
this.timeout(10000)
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID, { name: 'video 1 updated' })
+ await updateVideo(servers[0].url, servers[0].accessToken, videoUUID, { name: 'video 1 updated' })
await waitJobs(servers)
it('Should delete videos', async function () {
this.timeout(10000)
- await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoUUID)
- await removeVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAudioUUID)
+ await removeVideo(servers[0].url, servers[0].accessToken, videoUUID)
+ await removeVideo(servers[0].url, servers[0].accessToken, videoAudioUUID)
await waitJobs(servers)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
getVideo,
getVideosList,
immutableAssign,
- killallServers,
ServerInfo,
setAccessTokensToServers
} from '../../../../shared/extra-utils'
import { waitJobs } from '../../../../shared/extra-utils/server/jobs'
-import { getMagnetURI, getYoutubeVideoUrl, importVideo, getMyVideoImports } from '../../../../shared/extra-utils/videos/video-imports'
+import { getMagnetURI, getMyVideoImports, getYoutubeVideoUrl, importVideo } from '../../../../shared/extra-utils/videos/video-imports'
const expect = chai.expect
{
const res = await getMyUserInformation(servers[0].url, servers[0].accessToken)
- channelIdServer1 = res.body.videoChannels[ 0 ].id
+ channelIdServer1 = res.body.videoChannels[0].id
}
{
const res = await getMyUserInformation(servers[1].url, servers[1].accessToken)
- channelIdServer2 = res.body.videoChannels[ 0 ].id
+ channelIdServer2 = res.body.videoChannels[0].id
}
await doubleFollow(servers[0], servers[1])
await checkVideoServer2(server.url, res.body.data[0].uuid)
- const [ ,videoHttp, videoMagnet, videoTorrent ] = res.body.data
+ const [ , videoHttp, videoMagnet, videoTorrent ] = res.body.data
await checkVideosServer1(server.url, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid)
}
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(1)
- expect(videos[ 0 ].name).to.equal('normal')
+ expect(videos[0].name).to.equal('normal')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
}
})
})
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(1)
- expect(videos[ 0 ].name).to.equal('normal')
+ expect(videos[0].name).to.equal('normal')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
})
it('Should display NSFW videos when the nsfw param === true', async function () {
const videos = res.body.data
expect(videos).to.have.lengthOf(1)
- expect(videos[ 0 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('nsfw')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(1)
- expect(videos[ 0 ].name).to.equal('normal')
+ expect(videos[0].name).to.equal('normal')
}
})
const videos = res.body.data
expect(videos).to.have.lengthOf(2)
- expect(videos[ 0 ].name).to.equal('normal')
- expect(videos[ 1 ].name).to.equal('nsfw')
+ expect(videos[0].name).to.equal('normal')
+ expect(videos[1].name).to.equal('nsfw')
}
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
createVideoPlaylist,
doubleFollow,
flushAndRunMultipleServers,
- getVideoPlaylistsList, removeVideoFromPlaylist,
+ getVideoPlaylistsList,
+ removeVideoFromPlaylist,
+ reorderVideosPlaylist,
ServerInfo,
setAccessTokensToServers,
setDefaultVideoChannel,
testImage,
uploadVideoAndGetId,
- waitJobs,
- reorderVideosPlaylist
+ waitJobs
} from '../../../../shared/extra-utils'
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
this.timeout(30000)
const res = await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist without thumbnail',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 1 ].videoChannel.id
+ videoChannelId: servers[1].videoChannel.id
}
})
playlistWithoutThumbnail = res.body.videoPlaylist.id
const res2 = await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithoutThumbnail,
elementAttrs: { videoId: video1 }
})
this.timeout(30000)
const res = await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist with thumbnail',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 1 ].videoChannel.id,
+ videoChannelId: servers[1].videoChannel.id,
thumbnailfile: 'thumbnail.jpg'
}
})
playlistWithThumbnail = res.body.videoPlaylist.id
const res2 = await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithThumbnail,
elementAttrs: { videoId: video1 }
})
this.timeout(30000)
const res = await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithoutThumbnail,
elementAttrs: { videoId: video2 }
})
this.timeout(30000)
const res = await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithThumbnail,
elementAttrs: { videoId: video2 }
})
this.timeout(30000)
await removeVideoFromPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithoutThumbnail,
playlistElementId: withoutThumbnailE1
})
this.timeout(30000)
await removeVideoFromPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithThumbnail,
playlistElementId: withThumbnailE1
})
this.timeout(30000)
await removeVideoFromPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithoutThumbnail,
playlistElementId: withoutThumbnailE2
})
this.timeout(30000)
await removeVideoFromPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: playlistWithThumbnail,
playlistElementId: withThumbnailE2
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
servers[2].videos = await Promise.all(serverPromises[2])
}
- nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[ 0 ], videoName: 'NSFW video', nsfw: true })).id
+ nsfwVideoServer1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'NSFW video', nsfw: true })).id
{
await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: 'user1',
password: 'password'
})
describe('Get default playlists', function () {
it('Should list video playlist privacies', async function () {
- const res = await getVideoPlaylistPrivacies(servers[ 0 ].url)
+ const res = await getVideoPlaylistPrivacies(servers[0].url)
const privacies = res.body
expect(Object.keys(privacies)).to.have.length.at.least(3)
- expect(privacies[ 3 ]).to.equal('Private')
+ expect(privacies[3]).to.equal('Private')
})
it('Should list watch later playlist', async function () {
- const url = servers[ 0 ].url
- const accessToken = servers[ 0 ].accessToken
+ const url = servers[0].url
+ const accessToken = servers[0].accessToken
{
const res = await getAccountPlaylistsListWithToken(url, accessToken, 'root', 0, 5, VideoPlaylistType.WATCH_LATER)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
- const playlist: VideoPlaylist = res.body.data[ 0 ]
+ const playlist: VideoPlaylist = res.body.data[0]
expect(playlist.displayName).to.equal('Watch later')
expect(playlist.type.id).to.equal(VideoPlaylistType.WATCH_LATER)
expect(playlist.type.label).to.equal('Watch later')
})
it('Should get private playlist for a classic user', async function () {
- const token = await generateUserAccessToken(servers[ 0 ], 'toto')
+ const token = await generateUserAccessToken(servers[0], 'toto')
- const res = await getAccountPlaylistsListWithToken(servers[ 0 ].url, token, 'toto', 0, 5)
+ const res = await getAccountPlaylistsListWithToken(servers[0].url, token, 'toto', 0, 5)
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
- const playlistId = res.body.data[ 0 ].id
- await getPlaylistVideos(servers[ 0 ].url, token, playlistId, 0, 5)
+ const playlistId = res.body.data[0].id
+ await getPlaylistVideos(servers[0].url, token, playlistId, 0, 5)
})
})
this.timeout(30000)
await createVideoPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistAttrs: {
displayName: 'my super playlist',
privacy: VideoPlaylistPrivacy.PUBLIC,
description: 'my super description',
thumbnailfile: 'thumbnail.jpg',
- videoChannelId: servers[ 0 ].videoChannel.id
+ videoChannelId: servers[0].videoChannel.id
}
})
expect(res.body.total).to.equal(1)
expect(res.body.data).to.have.lengthOf(1)
- const playlistFromList = res.body.data[ 0 ] as VideoPlaylist
+ const playlistFromList = res.body.data[0] as VideoPlaylist
const res2 = await getVideoPlaylist(server.url, playlistFromList.uuid)
const playlistFromGet = res2.body
{
const res = await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist 2',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 1 ].videoChannel.id
+ videoChannelId: servers[1].videoChannel.id
}
})
playlistServer2Id1 = res.body.videoPlaylist.id
{
const res = await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist 3',
privacy: VideoPlaylistPrivacy.PUBLIC,
thumbnailfile: 'thumbnail.jpg',
- videoChannelId: servers[ 1 ].videoChannel.id
+ videoChannelId: servers[1].videoChannel.id
}
})
playlistServer2UUID2 = res.body.videoPlaylist.uuid
}
- for (let id of [ playlistServer2Id1, playlistServer2Id2 ]) {
+ for (const id of [ playlistServer2Id1, playlistServer2Id2 ]) {
await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: id,
- elementAttrs: { videoId: servers[ 1 ].videos[ 0 ].id, startTimestamp: 1, stopTimestamp: 2 }
+ elementAttrs: { videoId: servers[1].videos[0].id, startTimestamp: 1, stopTimestamp: 2 }
})
await addVideoInPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistId: id,
- elementAttrs: { videoId: servers[ 1 ].videos[ 1 ].id }
+ elementAttrs: { videoId: servers[1].videos[1].id }
})
}
await waitJobs(servers)
- for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
+ for (const server of [ servers[0], servers[1] ]) {
const res = await getVideoPlaylistsList(server.url, 0, 5)
const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
await testImage(server.url, 'thumbnail', playlist3.thumbnailPath)
}
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
+ const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
expect(res.body.data.find(p => p.displayName === 'playlist 2')).to.be.undefined
expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.be.undefined
})
this.timeout(30000)
// Server 2 and server 3 follow each other
- await doubleFollow(servers[ 1 ], servers[ 2 ])
+ await doubleFollow(servers[1], servers[2])
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
+ const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
const playlist2 = res.body.data.find(p => p.displayName === 'playlist 2')
expect(playlist2).to.not.be.undefined
- await testImage(servers[ 2 ].url, 'thumbnail-playlist', playlist2.thumbnailPath)
+ await testImage(servers[2].url, 'thumbnail-playlist', playlist2.thumbnailPath)
expect(res.body.data.find(p => p.displayName === 'playlist 3')).to.not.be.undefined
})
this.timeout(30000)
{
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, 'createdAt')
+ const res = await getVideoPlaylistsList(servers[2].url, 1, 2, 'createdAt')
expect(res.body.total).to.equal(3)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(2)
- expect(data[ 0 ].displayName).to.equal('playlist 2')
- expect(data[ 1 ].displayName).to.equal('playlist 3')
+ expect(data[0].displayName).to.equal('playlist 2')
+ expect(data[1].displayName).to.equal('playlist 3')
}
{
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 1, 2, '-createdAt')
+ const res = await getVideoPlaylistsList(servers[2].url, 1, 2, '-createdAt')
expect(res.body.total).to.equal(3)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(2)
- expect(data[ 0 ].displayName).to.equal('playlist 2')
- expect(data[ 1 ].displayName).to.equal('my super playlist')
+ expect(data[0].displayName).to.equal('playlist 2')
+ expect(data[1].displayName).to.equal('my super playlist')
}
})
this.timeout(30000)
{
- const res = await getVideoChannelPlaylistsList(servers[ 0 ].url, 'root_channel', 0, 2, '-createdAt')
+ const res = await getVideoChannelPlaylistsList(servers[0].url, 'root_channel', 0, 2, '-createdAt')
expect(res.body.total).to.equal(1)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(1)
- expect(data[ 0 ].displayName).to.equal('my super playlist')
+ expect(data[0].displayName).to.equal('my super playlist')
}
})
this.timeout(30000)
{
- const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, '-createdAt')
+ const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, '-createdAt')
expect(res.body.total).to.equal(2)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(1)
- expect(data[ 0 ].displayName).to.equal('playlist 2')
+ expect(data[0].displayName).to.equal('playlist 2')
}
{
- const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 1, 2, 'createdAt')
+ const res = await getAccountPlaylistsList(servers[1].url, 'root', 1, 2, 'createdAt')
expect(res.body.total).to.equal(2)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(1)
- expect(data[ 0 ].displayName).to.equal('playlist 3')
+ expect(data[0].displayName).to.equal('playlist 3')
}
{
- const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '3')
+ const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '3')
expect(res.body.total).to.equal(1)
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(1)
- expect(data[ 0 ].displayName).to.equal('playlist 3')
+ expect(data[0].displayName).to.equal('playlist 3')
}
{
- const res = await getAccountPlaylistsList(servers[ 1 ].url, 'root', 0, 10, 'createdAt', '4')
+ const res = await getAccountPlaylistsList(servers[1].url, 'root', 0, 10, 'createdAt', '4')
expect(res.body.total).to.equal(0)
this.timeout(30000)
await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist unlisted',
privacy: VideoPlaylistPrivacy.UNLISTED
})
await createVideoPlaylist({
- url: servers[ 1 ].url,
- token: servers[ 1 ].accessToken,
+ url: servers[1].url,
+ token: servers[1].accessToken,
playlistAttrs: {
displayName: 'playlist private',
privacy: VideoPlaylistPrivacy.PRIVATE
for (const server of servers) {
const results = [
- await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[ 1 ].port, 0, 5, '-createdAt'),
+ await getAccountPlaylistsList(server.url, 'root@localhost:' + servers[1].port, 0, 5, '-createdAt'),
await getVideoPlaylistsList(server.url, 0, 2, '-createdAt')
]
- expect(results[ 0 ].body.total).to.equal(2)
- expect(results[ 1 ].body.total).to.equal(3)
+ expect(results[0].body.total).to.equal(2)
+ expect(results[1].body.total).to.equal(3)
for (const res of results) {
const data: VideoPlaylist[] = res.body.data
expect(data).to.have.lengthOf(2)
- expect(data[ 0 ].displayName).to.equal('playlist 3')
- expect(data[ 1 ].displayName).to.equal('playlist 2')
+ expect(data[0].displayName).to.equal('playlist 3')
+ expect(data[1].displayName).to.equal('playlist 2')
}
}
})
this.timeout(30000)
const addVideo = (elementAttrs: any) => {
- return addVideoInPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: playlistServer1Id, elementAttrs })
+ return addVideoInPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: playlistServer1Id, elementAttrs })
}
const res = await createVideoPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistAttrs: {
displayName: 'playlist 4',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 0 ].videoChannel.id
+ videoChannelId: servers[0].videoChannel.id
}
})
playlistServer1Id = res.body.videoPlaylist.id
playlistServer1UUID = res.body.videoPlaylist.uuid
- await addVideo({ videoId: servers[ 0 ].videos[ 0 ].uuid, startTimestamp: 15, stopTimestamp: 28 })
- await addVideo({ videoId: servers[ 2 ].videos[ 1 ].uuid, startTimestamp: 35 })
- await addVideo({ videoId: servers[ 2 ].videos[ 2 ].uuid })
+ await addVideo({ videoId: servers[0].videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
+ await addVideo({ videoId: servers[2].videos[1].uuid, startTimestamp: 35 })
+ await addVideo({ videoId: servers[2].videos[2].uuid })
{
- const res = await addVideo({ videoId: servers[ 0 ].videos[ 3 ].uuid, stopTimestamp: 35 })
+ const res = await addVideo({ videoId: servers[0].videos[3].uuid, stopTimestamp: 35 })
playlistElementServer1Video4 = res.body.videoPlaylistElement.id
}
{
- const res = await addVideo({ videoId: servers[ 0 ].videos[ 4 ].uuid, startTimestamp: 45, stopTimestamp: 60 })
+ const res = await addVideo({ videoId: servers[0].videos[4].uuid, startTimestamp: 45, stopTimestamp: 60 })
playlistElementServer1Video5 = res.body.videoPlaylistElement.id
}
const videoElements: VideoPlaylistElement[] = res.body.data
expect(videoElements).to.have.lengthOf(6)
- expect(videoElements[ 0 ].video.name).to.equal('video 0 server 1')
- expect(videoElements[ 0 ].position).to.equal(1)
- expect(videoElements[ 0 ].startTimestamp).to.equal(15)
- expect(videoElements[ 0 ].stopTimestamp).to.equal(28)
+ expect(videoElements[0].video.name).to.equal('video 0 server 1')
+ expect(videoElements[0].position).to.equal(1)
+ expect(videoElements[0].startTimestamp).to.equal(15)
+ expect(videoElements[0].stopTimestamp).to.equal(28)
- expect(videoElements[ 1 ].video.name).to.equal('video 1 server 3')
- expect(videoElements[ 1 ].position).to.equal(2)
- expect(videoElements[ 1 ].startTimestamp).to.equal(35)
- expect(videoElements[ 1 ].stopTimestamp).to.be.null
+ expect(videoElements[1].video.name).to.equal('video 1 server 3')
+ expect(videoElements[1].position).to.equal(2)
+ expect(videoElements[1].startTimestamp).to.equal(35)
+ expect(videoElements[1].stopTimestamp).to.be.null
- expect(videoElements[ 2 ].video.name).to.equal('video 2 server 3')
- expect(videoElements[ 2 ].position).to.equal(3)
- expect(videoElements[ 2 ].startTimestamp).to.be.null
- expect(videoElements[ 2 ].stopTimestamp).to.be.null
+ expect(videoElements[2].video.name).to.equal('video 2 server 3')
+ expect(videoElements[2].position).to.equal(3)
+ expect(videoElements[2].startTimestamp).to.be.null
+ expect(videoElements[2].stopTimestamp).to.be.null
- expect(videoElements[ 3 ].video.name).to.equal('video 3 server 1')
- expect(videoElements[ 3 ].position).to.equal(4)
- expect(videoElements[ 3 ].startTimestamp).to.be.null
- expect(videoElements[ 3 ].stopTimestamp).to.equal(35)
+ expect(videoElements[3].video.name).to.equal('video 3 server 1')
+ expect(videoElements[3].position).to.equal(4)
+ expect(videoElements[3].startTimestamp).to.be.null
+ expect(videoElements[3].stopTimestamp).to.equal(35)
- expect(videoElements[ 4 ].video.name).to.equal('video 4 server 1')
- expect(videoElements[ 4 ].position).to.equal(5)
- expect(videoElements[ 4 ].startTimestamp).to.equal(45)
- expect(videoElements[ 4 ].stopTimestamp).to.equal(60)
+ expect(videoElements[4].video.name).to.equal('video 4 server 1')
+ expect(videoElements[4].position).to.equal(5)
+ expect(videoElements[4].startTimestamp).to.equal(45)
+ expect(videoElements[4].stopTimestamp).to.equal(60)
- expect(videoElements[ 5 ].video.name).to.equal('NSFW video')
- expect(videoElements[ 5 ].position).to.equal(6)
- expect(videoElements[ 5 ].startTimestamp).to.equal(5)
- expect(videoElements[ 5 ].stopTimestamp).to.be.null
+ expect(videoElements[5].video.name).to.equal('NSFW video')
+ expect(videoElements[5].position).to.equal(6)
+ expect(videoElements[5].startTimestamp).to.equal(5)
+ expect(videoElements[5].stopTimestamp).to.be.null
const res3 = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 2)
expect(res3.body.data).to.have.lengthOf(2)
before(async function () {
this.timeout(30000)
- groupUser1 = [ Object.assign({}, servers[ 0 ], { accessToken: userAccessTokenServer1 }) ]
- groupWithoutToken1 = [ Object.assign({}, servers[ 0 ], { accessToken: undefined }) ]
- group1 = [ servers[ 0 ] ]
- group2 = [ servers[ 1 ], servers[ 2 ] ]
+ groupUser1 = [ Object.assign({}, servers[0], { accessToken: userAccessTokenServer1 }) ]
+ groupWithoutToken1 = [ Object.assign({}, servers[0], { accessToken: undefined }) ]
+ group1 = [ servers[0] ]
+ group2 = [ servers[1], servers[2] ]
const res = await createVideoPlaylist({
- url: servers[ 0 ].url,
+ url: servers[0].url,
token: userAccessTokenServer1,
playlistAttrs: {
displayName: 'playlist 56',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 0 ].videoChannel.id
+ videoChannelId: servers[0].videoChannel.id
}
})
playlistServer1UUID2 = res.body.videoPlaylist.uuid
const addVideo = (elementAttrs: any) => {
- return addVideoInPlaylist({ url: servers[ 0 ].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
+ return addVideoInPlaylist({ url: servers[0].url, token: userAccessTokenServer1, playlistId: playlistServer1Id2, elementAttrs })
}
video1 = (await uploadVideoAndGetId({ server: servers[0], videoName: 'video 89', token: userAccessTokenServer1 })).uuid
const position = 1
{
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
+ await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PRIVATE })
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
}
{
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
+ await updateVideo(servers[0].url, servers[0].accessToken, video1, { privacy: VideoPrivacy.PUBLIC })
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
const position = 1
{
- await addVideoToBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1, 'reason', true)
+ await addVideoToBlacklist(servers[0].url, servers[0].accessToken, video1, 'reason', true)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
}
{
- await removeVideoFromBlacklist(servers[ 0 ].url, servers[ 0 ].accessToken, video1)
+ await removeVideoFromBlacklist(servers[0].url, servers[0].accessToken, video1)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
const position = 2
{
- await addAccountToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
+ await addAccountToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
- await removeAccountFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
+ await removeAccountFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'root@localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
}
{
- await addServerToAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
+ await addServerToAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
- await removeServerFromAccountBlocklist(servers[ 0 ].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
+ await removeServerFromAccountBlocklist(servers[0].url, userAccessTokenServer1, 'localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
}
{
- await addAccountToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
+ await addAccountToServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
- await removeAccountFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'root@localhost:' + servers[1].port)
+ await removeAccountFromServerBlocklist(servers[0].url, servers[0].accessToken, 'root@localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
}
{
- await addServerToServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await addServerToServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(groupUser1, playlistServer1UUID2, VideoPlaylistElementType.UNAVAILABLE, position, name, 3)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
- await removeServerFromServerBlocklist(servers[ 0 ].url, servers[ 0 ].accessToken, 'localhost:' + servers[1].port)
+ await removeServerFromServerBlocklist(servers[0].url, servers[0].accessToken, 'localhost:' + servers[1].port)
await waitJobs(servers)
await checkPlaylistElementType(group2, playlistServer1UUID2, VideoPlaylistElementType.REGULAR, position, name, 3)
{
await reorderVideosPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
elementAttrs: {
startPosition: 2,
{
await reorderVideosPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
elementAttrs: {
startPosition: 1,
{
await reorderVideosPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
elementAttrs: {
startPosition: 6,
])
for (let i = 1; i <= elements.length; i++) {
- expect(elements[ i - 1 ].position).to.equal(i)
+ expect(elements[i - 1].position).to.equal(i)
}
}
}
this.timeout(30000)
await updateVideoPlaylistElement({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
playlistElementId: playlistElementServer1Video4,
elementAttrs: {
})
await updateVideoPlaylistElement({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
playlistElementId: playlistElementServer1Video5,
elementAttrs: {
const res = await getPlaylistVideos(server.url, server.accessToken, playlistServer1UUID, 0, 10)
const elements: VideoPlaylistElement[] = res.body.data
- expect(elements[ 0 ].video.name).to.equal('video 3 server 1')
- expect(elements[ 0 ].position).to.equal(1)
- expect(elements[ 0 ].startTimestamp).to.equal(1)
- expect(elements[ 0 ].stopTimestamp).to.equal(35)
+ expect(elements[0].video.name).to.equal('video 3 server 1')
+ expect(elements[0].position).to.equal(1)
+ expect(elements[0].startTimestamp).to.equal(1)
+ expect(elements[0].stopTimestamp).to.equal(35)
- expect(elements[ 5 ].video.name).to.equal('video 4 server 1')
- expect(elements[ 5 ].position).to.equal(6)
- expect(elements[ 5 ].startTimestamp).to.equal(45)
- expect(elements[ 5 ].stopTimestamp).to.be.null
+ expect(elements[5].video.name).to.equal('video 4 server 1')
+ expect(elements[5].position).to.equal(6)
+ expect(elements[5].startTimestamp).to.equal(45)
+ expect(elements[5].stopTimestamp).to.be.null
}
})
it('Should check videos existence in my playlist', async function () {
const videoIds = [
- servers[ 0 ].videos[ 0 ].id,
+ servers[0].videos[0].id,
42000,
- servers[ 0 ].videos[ 3 ].id,
+ servers[0].videos[3].id,
43000,
- servers[ 0 ].videos[ 4 ].id
+ servers[0].videos[4].id
]
- const res = await doVideosExistInMyPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, videoIds)
+ const res = await doVideosExistInMyPlaylist(servers[0].url, servers[0].accessToken, videoIds)
const obj = res.body as VideoExistInPlaylist
{
- const elem = obj[ servers[ 0 ].videos[ 0 ].id ]
+ const elem = obj[servers[0].videos[0].id]
expect(elem).to.have.lengthOf(1)
- expect(elem[ 0 ].playlistElementId).to.exist
- expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
- expect(elem[ 0 ].startTimestamp).to.equal(15)
- expect(elem[ 0 ].stopTimestamp).to.equal(28)
+ expect(elem[0].playlistElementId).to.exist
+ expect(elem[0].playlistId).to.equal(playlistServer1Id)
+ expect(elem[0].startTimestamp).to.equal(15)
+ expect(elem[0].stopTimestamp).to.equal(28)
}
{
- const elem = obj[ servers[ 0 ].videos[ 3 ].id ]
+ const elem = obj[servers[0].videos[3].id]
expect(elem).to.have.lengthOf(1)
- expect(elem[ 0 ].playlistElementId).to.equal(playlistElementServer1Video4)
- expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
- expect(elem[ 0 ].startTimestamp).to.equal(1)
- expect(elem[ 0 ].stopTimestamp).to.equal(35)
+ expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
+ expect(elem[0].playlistId).to.equal(playlistServer1Id)
+ expect(elem[0].startTimestamp).to.equal(1)
+ expect(elem[0].stopTimestamp).to.equal(35)
}
{
- const elem = obj[ servers[ 0 ].videos[ 4 ].id ]
+ const elem = obj[servers[0].videos[4].id]
expect(elem).to.have.lengthOf(1)
- expect(elem[ 0 ].playlistId).to.equal(playlistServer1Id)
- expect(elem[ 0 ].startTimestamp).to.equal(45)
- expect(elem[ 0 ].stopTimestamp).to.equal(null)
+ expect(elem[0].playlistId).to.equal(playlistServer1Id)
+ expect(elem[0].startTimestamp).to.equal(45)
+ expect(elem[0].stopTimestamp).to.equal(null)
}
- expect(obj[ 42000 ]).to.have.lengthOf(0)
- expect(obj[ 43000 ]).to.have.lengthOf(0)
+ expect(obj[42000]).to.have.lengthOf(0)
+ expect(obj[43000]).to.have.lengthOf(0)
})
it('Should automatically update updatedAt field of playlists', async function () {
- const server = servers[ 1 ]
- const videoId = servers[ 1 ].videos[ 5 ].id
+ const server = servers[1]
+ const videoId = servers[1].videos[5].id
async function getPlaylistNames () {
const res = await getAccountPlaylistsListWithToken(server.url, server.accessToken, 'root', 0, 5, undefined, '-updatedAt')
const element2 = res2.body.videoPlaylistElement.id
const names1 = await getPlaylistNames()
- expect(names1[ 0 ]).to.equal('playlist 3 updated')
- expect(names1[ 1 ]).to.equal('playlist 2')
+ expect(names1[0]).to.equal('playlist 3 updated')
+ expect(names1[1]).to.equal('playlist 2')
await removeVideoFromPlaylist({
url: server.url,
})
const names2 = await getPlaylistNames()
- expect(names2[ 0 ]).to.equal('playlist 2')
- expect(names2[ 1 ]).to.equal('playlist 3 updated')
+ expect(names2[0]).to.equal('playlist 2')
+ expect(names2[1]).to.equal('playlist 3 updated')
await removeVideoFromPlaylist({
url: server.url,
})
const names3 = await getPlaylistNames()
- expect(names3[ 0 ]).to.equal('playlist 3 updated')
- expect(names3[ 1 ]).to.equal('playlist 2')
+ expect(names3[0]).to.equal('playlist 3 updated')
+ expect(names3[1]).to.equal('playlist 2')
})
it('Should delete some elements', async function () {
this.timeout(30000)
await removeVideoFromPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
playlistElementId: playlistElementServer1Video4
})
await removeVideoFromPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistId: playlistServer1Id,
playlistElementId: playlistElementNSFW
})
const elements: VideoPlaylistElement[] = res.body.data
expect(elements).to.have.lengthOf(4)
- expect(elements[ 0 ].video.name).to.equal('video 0 server 1')
- expect(elements[ 0 ].position).to.equal(1)
+ expect(elements[0].video.name).to.equal('video 0 server 1')
+ expect(elements[0].position).to.equal(1)
- expect(elements[ 1 ].video.name).to.equal('video 2 server 3')
- expect(elements[ 1 ].position).to.equal(2)
+ expect(elements[1].video.name).to.equal('video 2 server 3')
+ expect(elements[1].position).to.equal(2)
- expect(elements[ 2 ].video.name).to.equal('video 1 server 3')
- expect(elements[ 2 ].position).to.equal(3)
+ expect(elements[2].video.name).to.equal('video 1 server 3')
+ expect(elements[2].position).to.equal(3)
- expect(elements[ 3 ].video.name).to.equal('video 4 server 1')
- expect(elements[ 3 ].position).to.equal(4)
+ expect(elements[3].video.name).to.equal('video 4 server 1')
+ expect(elements[3].position).to.equal(4)
}
})
this.timeout(30000)
const res = await createVideoPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistAttrs: {
displayName: 'my super public playlist',
privacy: VideoPlaylistPrivacy.PUBLIC,
- videoChannelId: servers[ 0 ].videoChannel.id
+ videoChannelId: servers[0].videoChannel.id
}
})
const videoPlaylistIds = res.body.videoPlaylist
}
const playlistAttrs = { privacy: VideoPlaylistPrivacy.PRIVATE }
- await updateVideoPlaylist({ url: servers[ 0 ].url, token: servers[ 0 ].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
+ await updateVideoPlaylist({ url: servers[0].url, token: servers[0].accessToken, playlistId: videoPlaylistIds.id, playlistAttrs })
await waitJobs(servers)
- for (const server of [ servers[ 1 ], servers[ 2 ] ]) {
+ for (const server of [ servers[1], servers[2] ]) {
await getVideoPlaylist(server.url, videoPlaylistIds.uuid, 404)
}
- await getVideoPlaylist(servers[ 0 ].url, videoPlaylistIds.uuid, 401)
+ await getVideoPlaylist(servers[0].url, videoPlaylistIds.uuid, 401)
- await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistIds.uuid, 200)
+ await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistIds.uuid, 200)
})
})
it('Should delete the playlist on server 1 and delete on server 2 and 3', async function () {
this.timeout(30000)
- await deleteVideoPlaylist(servers[ 0 ].url, servers[ 0 ].accessToken, playlistServer1Id)
+ await deleteVideoPlaylist(servers[0].url, servers[0].accessToken, playlistServer1Id)
await waitJobs(servers)
const finder = data => data.find(p => p.displayName === 'my super playlist')
{
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
+ const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
expect(res.body.total).to.equal(3)
expect(finder(res.body.data)).to.not.be.undefined
}
- await unfollow(servers[ 2 ].url, servers[ 2 ].accessToken, servers[ 0 ])
+ await unfollow(servers[2].url, servers[2].accessToken, servers[0])
{
- const res = await getVideoPlaylistsList(servers[ 2 ].url, 0, 5)
+ const res = await getVideoPlaylistsList(servers[2].url, 0, 5)
expect(res.body.total).to.equal(1)
expect(finder(res.body.data)).to.be.undefined
it('Should delete a channel and put the associated playlist in private mode', async function () {
this.timeout(30000)
- const res = await addVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'super_channel', displayName: 'super channel' })
+ const res = await addVideoChannel(servers[0].url, servers[0].accessToken, { name: 'super_channel', displayName: 'super channel' })
const videoChannelId = res.body.videoChannel.id
const res2 = await createVideoPlaylist({
- url: servers[ 0 ].url,
- token: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ token: servers[0].accessToken,
playlistAttrs: {
displayName: 'channel playlist',
privacy: VideoPlaylistPrivacy.PUBLIC,
await waitJobs(servers)
- await deleteVideoChannel(servers[ 0 ].url, servers[ 0 ].accessToken, 'super_channel')
+ await deleteVideoChannel(servers[0].url, servers[0].accessToken, 'super_channel')
await waitJobs(servers)
- const res3 = await getVideoPlaylistWithToken(servers[ 0 ].url, servers[ 0 ].accessToken, videoPlaylistUUID)
+ const res3 = await getVideoPlaylistWithToken(servers[0].url, servers[0].accessToken, videoPlaylistUUID)
expect(res3.body.displayName).to.equal('channel playlist')
expect(res3.body.privacy.id).to.equal(VideoPlaylistPrivacy.PRIVATE)
- await getVideoPlaylist(servers[ 1 ].url, videoPlaylistUUID, 404)
+ await getVideoPlaylist(servers[1].url, videoPlaylistUUID, 404)
})
it('Should delete an account and delete its playlists', async function () {
const user = { username: 'user_1', password: 'password' }
const res = await createUser({
- url: servers[ 0 ].url,
- accessToken: servers[ 0 ].accessToken,
+ url: servers[0].url,
+ accessToken: servers[0].accessToken,
username: user.username,
password: user.password
})
const userId = res.body.user.id
- const userAccessToken = await userLogin(servers[ 0 ], user)
+ const userAccessToken = await userLogin(servers[0], user)
- const resChannel = await getMyUserInformation(servers[ 0 ].url, userAccessToken)
- const userChannel = (resChannel.body as User).videoChannels[ 0 ]
+ const resChannel = await getMyUserInformation(servers[0].url, userAccessToken)
+ const userChannel = (resChannel.body as User).videoChannels[0]
await createVideoPlaylist({
- url: servers[ 0 ].url,
+ url: servers[0].url,
token: userAccessToken,
playlistAttrs: {
displayName: 'playlist to be deleted',
const finder = data => data.find(p => p.displayName === 'playlist to be deleted')
{
- for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
+ for (const server of [ servers[0], servers[1] ]) {
const res = await getVideoPlaylistsList(server.url, 0, 15)
expect(finder(res.body.data)).to.not.be.undefined
}
}
- await removeUser(servers[ 0 ].url, userId, servers[ 0 ].accessToken)
+ await removeUser(servers[0].url, userId, servers[0].accessToken)
await waitJobs(servers)
{
- for (const server of [ servers[ 0 ], servers[ 1 ] ]) {
+ for (const server of [ servers[0], servers[1] ]) {
const res = await getVideoPlaylistsList(server.url, 0, 15)
expect(finder(res.body.data)).to.be.undefined
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import {
cleanupTests,
flushAndRunMultipleServers,
- getVideosList, getVideosListWithToken,
+ getVideosList,
+ getVideosListWithToken,
ServerInfo,
setAccessTokensToServers,
uploadVideo
username: 'hello',
password: 'super password'
}
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: user.username, password: user.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: user.username, password: user.password })
anotherUserToken = await userLogin(servers[0], user)
await getVideoWithToken(servers[0].url, anotherUserToken, privateVideoUUID, 403)
privacy: VideoPrivacy.PUBLIC
}
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, privateVideoId, attribute)
+ await updateVideo(servers[0].url, servers[0].accessToken, privateVideoId, attribute)
}
{
name: 'internal video becomes public',
privacy: VideoPrivacy.PUBLIC
}
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, internalVideoId, attribute)
+ await updateVideo(servers[0].url, servers[0].accessToken, internalVideoId, attribute)
}
await waitJobs(servers)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
getMyVideos,
getVideosList,
getVideoWithToken,
- killallServers,
ServerInfo,
setAccessTokensToServers,
updateVideo,
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
for (const server of servers) {
const res = await getVideosList(server.url)
- const video = res.body.data[ 0 ]
+ const video = res.body.data[0]
const res2 = await getVideo(server.url, video.id)
const videoDetails = res2.body
expect(videoDetails.files).to.have.lengthOf(1)
- const magnetUri = videoDetails.files[ 0 ].magnetUri
+ const magnetUri = videoDetails.files[0].magnetUri
expect(magnetUri).to.match(/\.webm/)
const torrent = await webtorrentAdd(magnetUri, true)
expect(torrent.files).to.be.an('array')
expect(torrent.files.length).to.equal(1)
- expect(torrent.files[ 0 ].path).match(/\.webm$/)
+ expect(torrent.files[0].path).match(/\.webm$/)
}
})
expect(videoDetails.files).to.have.lengthOf(4)
- const magnetUri = videoDetails.files[ 0 ].magnetUri
+ const magnetUri = videoDetails.files[0].magnetUri
expect(magnetUri).to.match(/\.mp4/)
const torrent = await webtorrentAdd(magnetUri, true)
expect(torrent.files).to.be.an('array')
expect(torrent.files.length).to.equal(1)
- expect(torrent.files[ 0 ].path).match(/\.mp4$/)
+ expect(torrent.files[0].path).match(/\.mp4$/)
}
})
const probe = await audio.get(path)
if (probe.audioStream) {
- expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac')
- expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000)
+ expect(probe.audioStream['codec_name']).to.be.equal('aac')
+ expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000)
} else {
this.fail('Could not retrieve the audio stream on ' + probe.absolutePath)
}
const videoDetails: VideoDetails = res2.body
expect(videoDetails.files).to.have.lengthOf(4)
- expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62)
- expect(videoDetails.files[ 1 ].fps).to.be.below(31)
- expect(videoDetails.files[ 2 ].fps).to.be.below(31)
- expect(videoDetails.files[ 3 ].fps).to.be.below(31)
+ expect(videoDetails.files[0].fps).to.be.above(58).and.below(62)
+ expect(videoDetails.files[1].fps).to.be.below(31)
+ expect(videoDetails.files[2].fps).to.be.below(31)
+ expect(videoDetails.files[3].fps).to.be.below(31)
for (const resolution of [ '240', '360', '480' ]) {
const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
fixture: 'video_short1.webm',
waitTranscoding: true
}
- const resVideo = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes)
+ const resVideo = await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
const videoId = resVideo.body.video.uuid
// Should be in transcode state
- const { body } = await getVideo(servers[ 1 ].url, videoId)
+ const { body } = await getVideo(servers[1].url, videoId)
expect(body.name).to.equal('waiting video')
expect(body.state.id).to.equal(VideoState.TO_TRANSCODE)
expect(body.state.label).to.equal('To transcode')
const video = res.body.data.find(v => v.name === videoAttributes.name)
- for (const resolution of ['240', '360', '480', '720', '1080']) {
+ for (const resolution of [ '240', '360', '480', '720', '1080' ]) {
const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-' + resolution + '.mp4')
const bitrate = await getVideoFileBitrate(path)
const fps = await getVideoFileFPS(path)
fixture
}
- await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributes)
+ await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributes)
await waitJobs(servers)
expect(videoDetails.files).to.have.lengthOf(4)
- const magnetUri = videoDetails.files[ 0 ].magnetUri
+ const magnetUri = videoDetails.files[0].magnetUri
expect(magnetUri).to.contain('.mp4')
}
}
this.timeout(60000)
const videoAttributesArg = { name: 'audio_with_preview', previewfile: 'preview.jpg', fixture: 'sample.ogg' }
- await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
+ await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
await waitJobs(servers)
await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
- const magnetUri = videoDetails.files[ 0 ].magnetUri
+ const magnetUri = videoDetails.files[0].magnetUri
expect(magnetUri).to.contain('.mp4')
}
})
this.timeout(60000)
const videoAttributesArg = { name: 'audio_without_preview', fixture: 'sample.ogg' }
- await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, videoAttributesArg)
+ await uploadVideo(servers[1].url, servers[1].accessToken, videoAttributesArg)
await waitJobs(servers)
await makeGetRequest({ url: server.url, path: videoDetails.thumbnailPath, statusCodeExpected: 200 })
await makeGetRequest({ url: server.url, path: videoDetails.previewPath, statusCodeExpected: 200 })
- const magnetUri = videoDetails.files[ 0 ].magnetUri
+ const magnetUri = videoDetails.files[0].magnetUri
expect(magnetUri).to.contain('.mp4')
}
})
const video = res.body.data.find(v => v.name === videoAttributes.name)
{
- const path = join(root(), 'test' + servers[ 1 ].internalServerNumber, 'videos', video.uuid + '-240.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-240.mp4')
const fps = await getVideoFileFPS(path)
expect(fps).to.be.equal(25)
}
{
- const path = join(root(), 'test' + servers[ 1 ].internalServerNumber, 'videos', video.uuid + '-720.mp4')
+ const path = join(root(), 'test' + servers[1].internalServerNumber, 'videos', video.uuid + '-720.mp4')
const fps = await getVideoFileFPS(path)
expect(fps).to.be.equal(59)
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
createUser,
doubleFollow,
flushAndRunMultipleServers,
- flushTests,
- killallServers,
makeGetRequest,
ServerInfo,
setAccessTokensToServers,
const namesResults = await getVideosNames(server, server.accessToken, 'local')
for (const names of namesResults) {
expect(names).to.have.lengthOf(1)
- expect(names[ 0 ]).to.equal('public ' + server.serverNumber)
+ expect(names[0]).to.equal('public ' + server.serverNumber)
}
}
})
for (const names of namesResults) {
expect(names).to.have.lengthOf(3)
- expect(names[ 0 ]).to.equal('public ' + server.serverNumber)
- expect(names[ 1 ]).to.equal('unlisted ' + server.serverNumber)
- expect(names[ 2 ]).to.equal('private ' + server.serverNumber)
+ expect(names[0]).to.equal('public ' + server.serverNumber)
+ expect(names[1]).to.equal('unlisted ' + server.serverNumber)
+ expect(names[2]).to.equal('private ' + server.serverNumber)
}
}
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
import {
+ cleanupTests,
+ closeAllSequelize,
+ countVideoViewsOf,
+ doubleFollow,
flushAndRunMultipleServers,
- flushTests,
killallServers,
reRunServer,
- flushAndRunServer,
ServerInfo,
setAccessTokensToServers,
- uploadVideo, uploadVideoAndGetId, viewVideo, wait, countVideoViewsOf, doubleFollow, waitJobs, cleanupTests, closeAllSequelize
+ uploadVideoAndGetId,
+ viewVideo,
+ wait,
+ waitJobs
} from '../../../../shared/extra-utils'
-import { getVideosOverview } from '../../../../shared/extra-utils/overviews/overviews'
-import { VideosOverview } from '../../../../shared/models/overviews'
-import { listMyVideosHistory } from '../../../../shared/extra-utils/videos/video-history'
const expect = chai.expect
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
expect(videoDetail.files).to.have.lengthOf(2)
- const [originalVideo, transcodedVideo] = videoDetail.files
+ const [ originalVideo, transcodedVideo ] = videoDetail.files
assertVideoProperties(originalVideo, 720, 'webm', 218910)
assertVideoProperties(transcodedVideo, 480, 'webm', 69217)
const videoDetail: VideoDetails = (await getVideo(server.url, video.uuid)).body
expect(videoDetail.files).to.have.lengthOf(4)
- const [originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240] = videoDetail.files
+ const [ originalVideo, transcodedVideo420, transcodedVideo320, transcodedVideo240 ] = videoDetail.files
assertVideoProperties(originalVideo, 720, 'ogv', 140849)
assertVideoProperties(transcodedVideo420, 480, 'mp4')
assertVideoProperties(transcodedVideo320, 360, 'mp4')
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
doubleFollow,
execCLI,
flushAndRunMultipleServers,
- flushTests,
getEnvCli,
getVideo,
getVideosList,
- killallServers,
ServerInfo,
- setAccessTokensToServers, updateCustomSubConfig,
- uploadVideo, wait
+ setAccessTokensToServers,
+ updateCustomSubConfig,
+ uploadVideo
} from '../../../shared/extra-utils'
import { waitJobs } from '../../../shared/extra-utils/server/jobs'
describe('Test create transcoding jobs', function () {
let servers: ServerInfo[] = []
- let videosUUID: string[] = []
+ const videosUUID: string[] = []
const config = {
transcoding: {
await doubleFollow(servers[0], servers[1])
for (let i = 1; i <= 5; i++) {
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' + i })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' + i })
videosUUID.push(res.body.video.uuid)
}
const res = await getVideosList(server.url)
const videos = res.body.data
- let infoHashes: { [ id: number ]: string }
+ let infoHashes: { [id: number]: string }
for (const video of videos) {
const res2 = await getVideo(server.url, video.uuid)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
describe('Test optimize old videos', function () {
let servers: ServerInfo[] = []
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let video1UUID: string
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
let video2UUID: string
before(async function () {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { expect } from 'chai'
addVideoChannel,
buildAbsoluteFixturePath,
cleanupTests,
- createUser, doubleFollow,
+ createUser,
+ doubleFollow,
execCLI,
flushAndRunServer,
- getEnvCli, getLocalIdByUUID,
+ getEnvCli,
+ getLocalIdByUUID,
getVideo,
getVideosList,
- getVideosListWithToken, removeVideo,
+ removeVideo,
ServerInfo,
- setAccessTokensToServers, uploadVideo, uploadVideoAndGetId,
+ setAccessTokensToServers,
+ uploadVideoAndGetId,
userLogin,
waitJobs
} from '../../../shared/extra-utils'
const videos: Video[] = res.body.data
- const video: VideoDetails = (await getVideo(server.url, videos[ 0 ].uuid)).body
+ const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body
expect(video.name).to.equal('test upload')
expect(video.support).to.equal('support_text')
{
const env = getEnvCli(server)
- const params = `list-my-redundancies`
+ const params = 'list-my-redundancies'
const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`)
expect(stdout).to.contain('super video')
{
const env = getEnvCli(server)
- const params = `list-my-redundancies`
+ const params = 'list-my-redundancies'
const stdout = await execCLI(`${env} ${cmd} redundancy ${params}`)
expect(stdout).to.not.contain('super video')
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
execCLI,
flushAndRunMultipleServers,
getAccount,
- getEnvCli, makeGetRequest, makeRawRequest,
+ getEnvCli,
+ makeGetRequest,
ServerInfo,
- setAccessTokensToServers, setDefaultVideoChannel,
+ setAccessTokensToServers,
+ setDefaultVideoChannel,
updateMyAvatar,
uploadVideo,
wait
import { createFile, readdir } from 'fs-extra'
import * as uuidv4 from 'uuid/v4'
import { join } from 'path'
-import * as request from 'supertest'
const expect = chai.expect
describe('Test prune storage scripts', function () {
let servers: ServerInfo[]
- const badNames: { [ directory: string ]: string[] } = {}
+ const badNames: { [directory: string]: string[] } = {}
before(async function () {
this.timeout(120000)
// Lazy load the remote avatar
{
- const res = await getAccount(servers[ 0 ].url, 'root@localhost:' + servers[ 1 ].port)
+ const res = await getAccount(servers[0].url, 'root@localhost:' + servers[1].port)
const account: Account = res.body
await makeGetRequest({
- url: servers[ 0 ].url,
+ url: servers[0].url,
path: account.avatar.path,
statusCodeExpected: 200
})
}
{
- const res = await getAccount(servers[ 1 ].url, 'root@localhost:' + servers[ 0 ].port)
+ const res = await getAccount(servers[1].url, 'root@localhost:' + servers[0].port)
const account: Account = res.body
await makeGetRequest({
- url: servers[ 1 ].url,
+ url: servers[1].url,
path: account.avatar.path,
statusCodeExpected: 200
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
{
const attr = { username: 'john', password: 'password' }
- await createUser({ url: servers[ 0 ].url, accessToken: servers[ 0 ].accessToken, username: attr.username, password: attr.password })
+ await createUser({ url: servers[0].url, accessToken: servers[0].accessToken, username: attr.username, password: attr.password })
userAccessToken = await userLogin(servers[0], attr)
const res = await getMyUserInformation(servers[0].url, userAccessToken)
}
{
- await uploadVideo(servers[ 0 ].url, userAccessToken, { name: 'user video' })
+ await uploadVideo(servers[0].url, userAccessToken, { name: 'user video' })
}
{
description: 'my super description for server 1',
fixture: 'video_short.webm'
}
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoAttributes)
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, videoAttributes)
const videoId = res.body.video.id
- await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 1')
- await addVideoCommentThread(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, 'super comment 2')
+ await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 1')
+ await addVideoCommentThread(servers[0].url, servers[0].accessToken, videoId, 'super comment 2')
}
await waitJobs(servers)
it('Should be well formed XML (covers RSS 2.0 and ATOM 1.0 endpoints)', async function () {
for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) {
- const rss = await getXMLfeed(servers[ 0 ].url, feed)
+ const rss = await getXMLfeed(servers[0].url, feed)
expect(rss.text).xml.to.be.valid()
- const atom = await getXMLfeed(servers[ 0 ].url, feed, 'atom')
+ const atom = await getXMLfeed(servers[0].url, feed, 'atom')
expect(atom.text).xml.to.be.valid()
}
})
it('Should be well formed JSON (covers JSON feed 1.0 endpoint)', async function () {
for (const feed of [ 'video-comments' as 'video-comments', 'videos' as 'videos' ]) {
- const json = await getJSONfeed(servers[ 0 ].url, feed)
- expect(JSON.parse(json.text)).to.be.jsonSchema({ 'type': 'object' })
+ const json = await getJSONfeed(servers[0].url, feed)
+ expect(JSON.parse(json.text)).to.be.jsonSchema({ type: 'object' })
}
})
})
const json = await getJSONfeed(server.url, 'videos')
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(2)
- expect(jsonObj.items[ 0 ].attachments).to.exist
- expect(jsonObj.items[ 0 ].attachments.length).to.be.eq(1)
- expect(jsonObj.items[ 0 ].attachments[ 0 ].mime_type).to.be.eq('application/x-bittorrent')
- expect(jsonObj.items[ 0 ].attachments[ 0 ].size_in_bytes).to.be.eq(218910)
- expect(jsonObj.items[ 0 ].attachments[ 0 ].url).to.contain('720.torrent')
+ expect(jsonObj.items[0].attachments).to.exist
+ expect(jsonObj.items[0].attachments.length).to.be.eq(1)
+ expect(jsonObj.items[0].attachments[0].mime_type).to.be.eq('application/x-bittorrent')
+ expect(jsonObj.items[0].attachments[0].size_in_bytes).to.be.eq(218910)
+ expect(jsonObj.items[0].attachments[0].url).to.contain('720.torrent')
}
})
const json = await getJSONfeed(servers[0].url, 'videos', { accountId: rootAccountId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
- expect(jsonObj.items[ 0 ].author.name).to.equal('root')
+ expect(jsonObj.items[0].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[0].author.name).to.equal('root')
}
{
const json = await getJSONfeed(servers[0].url, 'videos', { accountId: userAccountId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('user video')
- expect(jsonObj.items[ 0 ].author.name).to.equal('john')
+ expect(jsonObj.items[0].title).to.equal('user video')
+ expect(jsonObj.items[0].author.name).to.equal('john')
}
for (const server of servers) {
const json = await getJSONfeed(server.url, 'videos', { accountName: 'root@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[0].title).to.equal('my super name for server 1')
}
{
const json = await getJSONfeed(server.url, 'videos', { accountName: 'john@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('user video')
+ expect(jsonObj.items[0].title).to.equal('user video')
}
}
})
const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: rootChannelId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
- expect(jsonObj.items[ 0 ].author.name).to.equal('root')
+ expect(jsonObj.items[0].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[0].author.name).to.equal('root')
}
{
const json = await getJSONfeed(servers[0].url, 'videos', { videoChannelId: userChannelId })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('user video')
- expect(jsonObj.items[ 0 ].author.name).to.equal('john')
+ expect(jsonObj.items[0].title).to.equal('user video')
+ expect(jsonObj.items[0].author.name).to.equal('john')
}
for (const server of servers) {
const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'root_channel@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('my super name for server 1')
+ expect(jsonObj.items[0].title).to.equal('my super name for server 1')
}
{
const json = await getJSONfeed(server.url, 'videos', { videoChannelName: 'john_channel@localhost:' + servers[0].port })
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(1)
- expect(jsonObj.items[ 0 ].title).to.equal('user video')
+ expect(jsonObj.items[0].title).to.equal('user video')
}
}
})
const jsonObj = JSON.parse(json.text)
expect(jsonObj.items.length).to.be.equal(2)
- expect(jsonObj.items[ 0 ].html_content).to.equal('super comment 2')
- expect(jsonObj.items[ 1 ].html_content).to.equal('super comment 1')
+ expect(jsonObj.items[0].html_content).to.equal('super comment 2')
+ expect(jsonObj.items[1].html_content).to.equal('super comment 1')
}
})
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
comment.text = '@florian @jean@localhost:9000 @flo @another@localhost:9000 @flo2@jean.com hello ' +
'email@localhost:9000 coucou.com no? @chocobozzz @chocobozzz @end'
- const result = comment.extractMentions().sort()
+ const result = comment.extractMentions().sort((a, b) => a.localeCompare(b))
expect(result).to.deep.equal([ 'another', 'chocobozzz', 'end', 'flo', 'florian', 'jean' ])
})
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import 'mocha'
import * as chai from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
-import * as chai from 'chai'
import 'mocha'
import {
cleanupTests,
createUser,
deleteVideoComment,
getPluginTestPath,
- installPlugin, login,
- registerUser, removeUser,
+ installPlugin,
+ registerUser,
+ removeUser,
setAccessTokensToServers,
- unblockUser, updateUser,
+ unblockUser,
+ updateUser,
updateVideo,
uploadVideo,
- viewVideo,
- userLogin
+ userLogin,
+ viewVideo
} from '../../../shared/extra-utils'
-const expect = chai.expect
-
describe('Test plugin action hooks', function () {
let servers: ServerInfo[]
let videoUUID: string
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
-import {
- cleanupTests,
- flushAndRunMultipleServers,
- flushAndRunServer, killallServers, reRunServer,
- ServerInfo,
- waitUntilLog
-} from '../../../shared/extra-utils/server/servers'
+import { cleanupTests, flushAndRunMultipleServers, ServerInfo } from '../../../shared/extra-utils/server/servers'
import {
addVideoCommentReply,
addVideoCommentThread,
- deleteVideoComment,
+ doubleFollow,
+ getConfig,
getPluginTestPath,
- getVideosList,
- installPlugin,
- removeVideo,
- setAccessTokensToServers,
- updateVideo,
- uploadVideo,
- viewVideo,
- getVideosListPagination,
getVideo,
getVideoCommentThreads,
+ getVideosList,
+ getVideosListPagination,
getVideoThreadComments,
getVideoWithToken,
+ installPlugin,
+ registerUser,
+ setAccessTokensToServers,
setDefaultVideoChannel,
- waitJobs,
- doubleFollow, getConfig, registerUser
+ updateVideo,
+ uploadVideo,
+ waitJobs
} from '../../../shared/extra-utils'
import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
import { VideoDetails } from '../../../shared/models/videos'
}
it('Should blacklist on upload', async function () {
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video please blacklist me' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video please blacklist me' })
await checkIsBlacklisted(res, true)
})
})
it('Should blacklist on update', async function () {
- const res = await uploadVideo(servers[ 0 ].url, servers[ 0 ].accessToken, { name: 'video' })
+ const res = await uploadVideo(servers[0].url, servers[0].accessToken, { name: 'video' })
const videoId = res.body.video.uuid
await checkIsBlacklisted(res, false)
- await updateVideo(servers[ 0 ].url, servers[ 0 ].accessToken, videoId, { name: 'please blacklist me' })
+ await updateVideo(servers[0].url, servers[0].accessToken, videoId, { name: 'please blacklist me' })
await checkIsBlacklisted(res, true)
})
it('Should blacklist on remote upload', async function () {
this.timeout(45000)
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'remote please blacklist me' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'remote please blacklist me' })
await waitJobs(servers)
await checkIsBlacklisted(res, true)
it('Should blacklist on remote update', async function () {
this.timeout(45000)
- const res = await uploadVideo(servers[ 1 ].url, servers[ 1 ].accessToken, { name: 'video' })
+ const res = await uploadVideo(servers[1].url, servers[1].accessToken, { name: 'video' })
await waitJobs(servers)
const videoId = res.body.video.uuid
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
+import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
import {
- cleanupTests,
- flushAndRunMultipleServers,
- flushAndRunServer, killallServers, reRunServer,
- ServerInfo,
- waitUntilLog
-} from '../../../shared/extra-utils/server/servers'
-import {
- addVideoCommentReply,
- addVideoCommentThread,
- deleteVideoComment,
getPluginTestPath,
- getVideosList,
+ getPluginTranslations,
installPlugin,
- removeVideo,
setAccessTokensToServers,
- updateVideo,
- uploadVideo,
- viewVideo,
- getVideosListPagination,
- getVideo,
- getVideoCommentThreads,
- getVideoThreadComments,
- getVideoWithToken,
- setDefaultVideoChannel,
- waitJobs,
- doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin, getPluginTranslations
+ uninstallPlugin
} from '../../../shared/extra-utils'
-import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
-import { VideoDetails } from '../../../shared/models/videos'
-import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports'
const expect = chai.expect
expect(res.body).to.deep.equal({
'peertube-plugin-test': {
- 'Hi': 'Coucou'
+ Hi: 'Coucou'
},
'peertube-plugin-test-two': {
'Hello world': 'Bonjour le monde'
expect(res.body).to.deep.equal({
'peertube-plugin-test': {
- 'Hi': 'Coucou'
+ Hi: 'Coucou'
}
})
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import 'mocha'
+import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
import {
- cleanupTests,
- flushAndRunMultipleServers,
- flushAndRunServer, killallServers, reRunServer,
- ServerInfo,
- waitUntilLog
-} from '../../../shared/extra-utils/server/servers'
-import {
- addVideoCommentReply,
- addVideoCommentThread,
- deleteVideoComment,
getPluginTestPath,
- getVideosList,
+ getVideo,
+ getVideoCategories,
+ getVideoLanguages,
+ getVideoLicences,
installPlugin,
- removeVideo,
setAccessTokensToServers,
- updateVideo,
- uploadVideo,
- viewVideo,
- getVideosListPagination,
- getVideo,
- getVideoCommentThreads,
- getVideoThreadComments,
- getVideoWithToken,
- setDefaultVideoChannel,
- waitJobs,
- doubleFollow, getVideoLanguages, getVideoLicences, getVideoCategories, uninstallPlugin
+ uninstallPlugin,
+ uploadVideo
} from '../../../shared/extra-utils'
-import { VideoCommentThreadTree } from '../../../shared/models/videos/video-comment.model'
import { VideoDetails } from '../../../shared/models/videos'
-import { getYoutubeVideoUrl, importVideo } from '../../../shared/extra-utils/videos/video-imports'
const expect = chai.expect
const res = await getVideoLanguages(server.url)
const languages = res.body
- expect(languages[ 'en' ]).to.equal('English')
- expect(languages[ 'fr' ]).to.equal('French')
+ expect(languages['en']).to.equal('English')
+ expect(languages['fr']).to.equal('French')
- expect(languages[ 'al_bhed' ]).to.not.exist
- expect(languages[ 'al_bhed2' ]).to.not.exist
+ expect(languages['al_bhed']).to.not.exist
+ expect(languages['al_bhed2']).to.not.exist
}
{
const res = await getVideoCategories(server.url)
const categories = res.body
- expect(categories[ 1 ]).to.equal('Music')
- expect(categories[ 2 ]).to.equal('Films')
+ expect(categories[1]).to.equal('Music')
+ expect(categories[2]).to.equal('Films')
- expect(categories[ 42 ]).to.not.exist
- expect(categories[ 43 ]).to.not.exist
+ expect(categories[42]).to.not.exist
+ expect(categories[43]).to.not.exist
}
{
const res = await getVideoLicences(server.url)
const licences = res.body
- expect(licences[ 1 ]).to.equal('Attribution')
- expect(licences[ 7 ]).to.equal('Public Domain Dedication')
+ expect(licences[1]).to.equal('Attribution')
+ expect(licences[7]).to.equal('Public Domain Dedication')
- expect(licences[ 42 ]).to.not.exist
- expect(licences[ 43 ]).to.not.exist
+ expect(licences[42]).to.not.exist
+ expect(licences[43]).to.not.exist
}
})
+++ /dev/null
-import { VideoRateType } from '../../../shared'
-import {
- addVideoChannel,
- createUser,
- flushTests,
- getVideosList,
- killallServers,
- rateVideo,
- flushAndRunServer,
- ServerInfo,
- setAccessTokensToServers,
- uploadVideo
-} from '../../../shared/extra-utils'
-import * as Bluebird from 'bluebird'
-
-start()
- .catch(err => console.error(err))
-
-// ----------------------------------------------------------------------------
-
-async function start () {
-
- console.log('Flushed tests.')
-
- const server = await flushAndRunServer(6)
-
- process.on('exit', async () => {
- killallServers([ server ])
- return
- })
- process.on('SIGINT', goodbye)
- process.on('SIGTERM', goodbye)
-
- await setAccessTokensToServers([ server ])
-
- console.log('Servers ran.')
-
- // Forever
- const fakeTab = Array.from(Array(1000000).keys())
- const funs = [
- uploadCustom
- // uploadCustom,
- // uploadCustom,
- // uploadCustom,
- // likeCustom,
- // createUserCustom,
- // createCustomChannel
- ]
- const promises = []
-
- for (const fun of funs) {
- promises.push(
- Bluebird.map(fakeTab, () => {
- return fun(server).catch(err => console.error(err))
- }, { concurrency: 3 })
- )
- }
-
- await Promise.all(promises)
-}
-
-function getRandomInt (min, max) {
- return Math.floor(Math.random() * (max - min)) + min
-}
-
-function createCustomChannel (server: ServerInfo) {
- const videoChannel = {
- name: Date.now().toString(),
- displayName: Date.now().toString(),
- description: Date.now().toString()
- }
-
- return addVideoChannel(server.url, server.accessToken, videoChannel)
-}
-
-function createUserCustom (server: ServerInfo) {
- const username = Date.now().toString() + getRandomInt(0, 100000)
- console.log('Creating user %s.', username)
-
- return createUser({ url: server.url, accessToken: server.accessToken, username: username, password: 'coucou' })
-}
-
-function uploadCustom (server: ServerInfo) {
- console.log('Uploading video.')
-
- const videoAttributes = {
- name: Date.now() + ' name',
- category: 4,
- nsfw: false,
- licence: 2,
- language: 'en',
- description: Date.now() + ' description',
- tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ],
- fixture: 'video_short.mp4'
- }
-
- return uploadVideo(server.url, server.accessToken, videoAttributes)
-}
-
-function likeCustom (server: ServerInfo) {
- return rateCustom(server, 'like')
-}
-
-function dislikeCustom (server: ServerInfo) {
- return rateCustom(server, 'dislike')
-}
-
-async function rateCustom (server: ServerInfo, rating: VideoRateType) {
- const res = await getVideosList(server.url)
-
- const videos = res.body.data
- if (videos.length === 0) return undefined
-
- const videoToRate = videos[getRandomInt(0, videos.length)]
-
- console.log('Rating (%s) video.', rating)
- return rateVideo(server.url, server.accessToken, videoToRate.id, rating)
-}
-
-function goodbye () {
- return process.exit(-1)
-}
+++ /dev/null
-// /!\ Before imports /!\
-process.env.NODE_ENV = 'test'
-
-import * as program from 'commander'
-import { Video, VideoFile, VideoRateType } from '../../../shared'
-import { JobState } from '../../../shared/models'
-import {
- flushAndRunMultipleServers,
- flushTests, follow,
- getVideo,
- getVideosList, getVideosListPagination,
- killallServers,
- removeVideo,
- ServerInfo as DefaultServerInfo,
- setAccessTokensToServers,
- updateVideo,
- uploadVideo, viewVideo,
- wait
-} from '../../../shared/extra-utils'
-import { getJobsListPaginationAndSort } from '../../../shared/extra-utils/server/jobs'
-
-interface ServerInfo extends DefaultServerInfo {
- requestsNumber: number
-}
-
-program
- .option('-c, --create [weight]', 'Weight for creating videos')
- .option('-r, --remove [weight]', 'Weight for removing videos')
- .option('-u, --update [weight]', 'Weight for updating videos')
- .option('-v, --view [weight]', 'Weight for viewing videos')
- .option('-l, --like [weight]', 'Weight for liking videos')
- .option('-s, --dislike [weight]', 'Weight for disliking videos')
- .option('-p, --servers [n]', 'Number of servers to run (3 or 6)', /^3|6$/, 3)
- .option('-i, --interval-action [interval]', 'Interval in ms for an action')
- .option('-I, --interval-integrity [interval]', 'Interval in ms for an integrity check')
- .option('-f, --flush', 'Flush data on exit')
- .option('-d, --difference', 'Display difference if integrity is not okay')
- .parse(process.argv)
-
-const createWeight = program['create'] !== undefined ? parseInt(program['create'], 10) : 5
-const removeWeight = program['remove'] !== undefined ? parseInt(program['remove'], 10) : 4
-const updateWeight = program['update'] !== undefined ? parseInt(program['update'], 10) : 4
-const viewWeight = program['view'] !== undefined ? parseInt(program['view'], 10) : 4
-const likeWeight = program['like'] !== undefined ? parseInt(program['like'], 10) : 4
-const dislikeWeight = program['dislike'] !== undefined ? parseInt(program['dislike'], 10) : 4
-const flushAtExit = program['flush'] || false
-const actionInterval = program['intervalAction'] !== undefined ? parseInt(program['intervalAction'], 10) : 500
-const integrityInterval = program['intervalIntegrity'] !== undefined ? parseInt(program['intervalIntegrity'], 10) : 60000
-const displayDiffOnFail = program['difference'] || false
-
-const numberOfServers = 6
-
-console.log(
- 'Create weight: %d, update weight: %d, remove weight: %d, view weight: %d, like weight: %d, dislike weight: %d.',
- createWeight, updateWeight, removeWeight, viewWeight, likeWeight, dislikeWeight
-)
-
-if (flushAtExit) {
- console.log('Program will flush data on exit.')
-} else {
- console.log('Program will not flush data on exit.')
-}
-if (displayDiffOnFail) {
- console.log('Program will display diff on failure.')
-} else {
- console.log('Program will not display diff on failure')
-}
-console.log('Interval in ms for each action: %d.', actionInterval)
-console.log('Interval in ms for each integrity check: %d.', integrityInterval)
-
-console.log('Run servers...')
-
-start()
-
-// ----------------------------------------------------------------------------
-
-async function start () {
- const servers = await runServers(numberOfServers)
-
- process.on('exit', async () => {
- await exitServers(servers, flushAtExit)
-
- return
- })
- process.on('SIGINT', goodbye)
- process.on('SIGTERM', goodbye)
-
- console.log('Servers ran')
- initializeRequestsPerServer(servers)
-
- let checking = false
-
- setInterval(async () => {
- if (checking === true) return
-
- const rand = getRandomInt(0, createWeight + updateWeight + removeWeight + viewWeight + likeWeight + dislikeWeight)
-
- const numServer = getRandomNumServer(servers)
- servers[numServer].requestsNumber++
-
- if (rand < createWeight) {
- await upload(servers, numServer)
- } else if (rand < createWeight + updateWeight) {
- await update(servers, numServer)
- } else if (rand < createWeight + updateWeight + removeWeight) {
- await remove(servers, numServer)
- } else if (rand < createWeight + updateWeight + removeWeight + viewWeight) {
- await view(servers, numServer)
- } else if (rand < createWeight + updateWeight + removeWeight + viewWeight + likeWeight) {
- await like(servers, numServer)
- } else {
- await dislike(servers, numServer)
- }
- }, actionInterval)
-
- // The function will check the consistency between servers (should have the same videos with same attributes...)
- setInterval(function () {
- if (checking === true) return
-
- console.log('Checking integrity...')
- checking = true
-
- const waitingInterval = setInterval(async () => {
- const pendingRequests = await isTherePendingRequests(servers)
- if (pendingRequests === true) {
- console.log('A server has pending requests, waiting...')
- return
- }
-
- // Even if there are no pending request, wait some potential processes
- await wait(2000)
- await checkIntegrity(servers)
-
- initializeRequestsPerServer(servers)
- checking = false
- clearInterval(waitingInterval)
- }, 10000)
- }, integrityInterval)
-}
-
-function initializeRequestsPerServer (servers: ServerInfo[]) {
- servers.forEach(server => server.requestsNumber = 0)
-}
-
-function getRandomInt (min, max) {
- return Math.floor(Math.random() * (max - min)) + min
-}
-
-function getRandomNumServer (servers) {
- return getRandomInt(0, servers.length)
-}
-
-async function runServers (numberOfServers: number) {
- const servers: ServerInfo[] = (await flushAndRunMultipleServers(numberOfServers))
- .map(s => Object.assign({ requestsNumber: 0 }, s))
-
- // Get the access tokens
- await setAccessTokensToServers(servers)
-
- for (let i = 0; i < numberOfServers; i++) {
- for (let j = 0; j < numberOfServers; j++) {
- if (i === j) continue
-
- await follow(servers[i].url, [ servers[j].url ], servers[i].accessToken)
- }
- }
-
- return servers
-}
-
-async function exitServers (servers: ServerInfo[], flushAtExit: boolean) {
- killallServers(servers)
-
- if (flushAtExit) await flushTests()
-}
-
-function upload (servers: ServerInfo[], numServer: number) {
- console.log('Uploading video to server ' + numServer)
-
- const videoAttributes = {
- name: Date.now() + ' name',
- category: 4,
- nsfw: false,
- licence: 2,
- language: 'en',
- description: Date.now() + ' description',
- tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ],
- fixture: 'video_short1.webm'
- }
- return uploadVideo(servers[numServer].url, servers[numServer].accessToken, videoAttributes)
-}
-
-async function update (servers: ServerInfo[], numServer: number) {
- const res = await getVideosList(servers[numServer].url)
-
- const videos = res.body.data.filter(video => video.isLocal === true)
- if (videos.length === 0) return undefined
-
- const toUpdate = videos[getRandomInt(0, videos.length)].id
- const attributes = {
- name: Date.now() + ' name',
- description: Date.now() + ' description',
- tags: [ Date.now().toString().substring(0, 5) + 't1', Date.now().toString().substring(0, 5) + 't2' ]
- }
-
- console.log('Updating video of server ' + numServer)
-
- return updateVideo(servers[numServer].url, servers[numServer].accessToken, toUpdate, attributes)
-}
-
-async function remove (servers: ServerInfo[], numServer: number) {
- const res = await getVideosList(servers[numServer].url)
- const videos = res.body.data.filter(video => video.isLocal === true)
- if (videos.length === 0) return undefined
-
- const toRemove = videos[getRandomInt(0, videos.length)].id
-
- console.log('Removing video from server ' + numServer)
- return removeVideo(servers[numServer].url, servers[numServer].accessToken, toRemove)
-}
-
-async function view (servers: ServerInfo[], numServer: number) {
- const res = await getVideosList(servers[numServer].url)
-
- const videos = res.body.data
- if (videos.length === 0) return undefined
-
- const toView = videos[getRandomInt(0, videos.length)].id
-
- console.log('Viewing video from server ' + numServer)
- return viewVideo(servers[numServer].url, toView)
-}
-
-function like (servers: ServerInfo[], numServer: number) {
- return rate(servers, numServer, 'like')
-}
-
-function dislike (servers: ServerInfo[], numServer: number) {
- return rate(servers, numServer, 'dislike')
-}
-
-async function rate (servers: ServerInfo[], numServer: number, rating: VideoRateType) {
- const res = await getVideosList(servers[numServer].url)
-
- const videos = res.body.data
- if (videos.length === 0) return undefined
-
- const toRate = videos[getRandomInt(0, videos.length)].id
-
- console.log('Rating (%s) video from server %d', rating, numServer)
- return getVideo(servers[numServer].url, toRate)
-}
-
-async function checkIntegrity (servers: ServerInfo[]) {
- const videos: Video[][] = []
- const tasks: Promise<any>[] = []
-
- // Fetch all videos and remove some fields that can differ between servers
- for (const server of servers) {
- const p = getVideosListPagination(server.url, 0, 1000000, '-createdAt')
- .then(res => videos.push(res.body.data))
- tasks.push(p)
- }
-
- await Promise.all(tasks)
-
- let i = 0
- for (const video of videos) {
- const differences = areDifferences(video, videos[0])
- if (differences !== undefined) {
- console.error('Integrity not ok with server %d!', i + 1)
-
- if (displayDiffOnFail) {
- console.log(differences)
- }
-
- process.exit(-1)
- }
-
- i++
- }
-
- console.log('Integrity ok.')
-}
-
-function areDifferences (videos1: Video[], videos2: Video[]) {
- // Remove some keys we don't want to compare
- videos1.concat(videos2).forEach(video => {
- delete video.id
- delete video.isLocal
- delete video.thumbnailPath
- delete video.updatedAt
- delete video.views
- })
-
- if (videos1.length !== videos2.length) {
- return `Videos length are different (${videos1.length}/${videos2.length}).`
- }
-
- for (const video1 of videos1) {
- const video2 = videos2.find(video => video.uuid === video1.uuid)
-
- if (!video2) return 'Video ' + video1.uuid + ' is missing.'
-
- for (const videoKey of Object.keys(video1)) {
- const attribute1 = video1[videoKey]
- const attribute2 = video2[videoKey]
-
- if (videoKey === 'tags') {
- if (attribute1.length !== attribute2.length) {
- return 'Tags are different.'
- }
-
- attribute1.forEach(tag1 => {
- if (attribute2.indexOf(tag1) === -1) {
- return 'Tag ' + tag1 + ' is missing.'
- }
- })
- } else if (videoKey === 'files') {
- if (attribute1.length !== attribute2.length) {
- return 'Video files are different.'
- }
-
- attribute1.forEach((videoFile1: VideoFile) => {
- const videoFile2: VideoFile = attribute2.find(videoFile => videoFile.magnetUri === videoFile1.magnetUri)
- if (!videoFile2) {
- return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.`
- }
-
- if (videoFile1.size !== videoFile2.size || videoFile1.resolution.label !== videoFile2.resolution.label) {
- return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.`
- }
- })
- } else {
- if (attribute1 !== attribute2) {
- return `Video ${video1.uuid} has different value for attribute ${videoKey}.`
- }
- }
- }
- }
-
- return undefined
-}
-
-function goodbye () {
- return process.exit(-1)
-}
-
-async function isTherePendingRequests (servers: ServerInfo[]) {
- const states: JobState[] = [ 'waiting', 'active', 'delayed' ]
- const tasks: Promise<any>[] = []
- let pendingRequests = false
-
- // Check if each server has pending request
- for (const server of servers) {
- for (const state of states) {
- const p = getJobsListPaginationAndSort({
- url: server.url,
- accessToken: server.accessToken,
- state: state,
- start: 0,
- count: 10,
- sort: '-createdAt'
- })
- .then(res => {
- if (res.body.total > 0) pendingRequests = true
- })
- tasks.push(p)
- }
- }
-
- await Promise.all(tasks)
-
- return pendingRequests
-}
}
interface Settings {
- remotes: any[],
+ remotes: any[]
default: number
}
if (!program['url'] || !program['username'] || !program['password']) {
// No remote and we don't have program parameters: quit
if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
- if (!program[ 'url' ]) console.error('--url field is required.')
- if (!program[ 'username' ]) console.error('--username field is required.')
- if (!program[ 'password' ]) console.error('--password field is required.')
+ if (!program['url']) console.error('--url field is required.')
+ if (!program['username']) console.error('--username field is required.')
+ if (!program['password']) console.error('--password field is required.')
return process.exit(-1)
}
}
return {
- url: program[ 'url' ],
- username: program[ 'username' ],
- password: program[ 'password' ]
+ url: program['url'],
+ username: program['username'],
+ password: program['password']
}
}
const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {}
for (const key of Object.keys(defaultBooleanAttributes)) {
- if (command[ key ] !== undefined) {
- booleanAttributes[key] = command[ key ]
+ if (command[key] !== undefined) {
+ booleanAttributes[key] = command[key]
} else if (defaultAttributes[key] !== undefined) {
booleanAttributes[key] = defaultAttributes[key]
} else {
}
const videoAttributes = {
- name: command[ 'videoName' ] || defaultAttributes.name,
- category: command[ 'category' ] || defaultAttributes.category || undefined,
- licence: command[ 'licence' ] || defaultAttributes.licence || undefined,
- language: command[ 'language' ] || defaultAttributes.language || undefined,
- privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
- support: command[ 'support' ] || defaultAttributes.support || undefined,
- description: command[ 'videoDescription' ] || defaultAttributes.description || undefined,
- tags: command[ 'tags' ] || defaultAttributes.tags || undefined
+ name: command['videoName'] || defaultAttributes.name,
+ category: command['category'] || defaultAttributes.category || undefined,
+ licence: command['licence'] || defaultAttributes.licence || undefined,
+ language: command['language'] || defaultAttributes.language || undefined,
+ privacy: command['privacy'] || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
+ support: command['support'] || defaultAttributes.support || undefined,
+ description: command['videoDescription'] || defaultAttributes.description || undefined,
+ tags: command['tags'] || defaultAttributes.tags || undefined
}
Object.assign(videoAttributes, booleanAttributes)
- if (command[ 'channelName' ]) {
+ if (command['channelName']) {
const res = await getVideoChannel(url, command['channelName'])
const videoChannel: VideoChannel = res.body
function getServerCredentials (program: any) {
return Promise.all([ getSettings(), getNetrc() ])
- .then(([ settings, netrc ]) => {
- return getRemoteObjectOrDie(program, settings, netrc)
- })
+ .then(([ settings, netrc ]) => {
+ return getRemoteObjectOrDie(program, settings, netrc)
+ })
}
function getLogger (logLevel = 'info') {
+// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
+
import { registerTSPaths } from '../helpers/register-ts-paths'
registerTSPaths()
import * as prompt from 'prompt'
import { getNetrc, getSettings, writeSettings } from './cli'
import { isUserUsernameValid } from '../helpers/custom-validators/users'
-import { getAccessToken, login } from '../../shared/extra-utils'
+import { getAccessToken } from '../../shared/extra-utils'
import * as CliTable3 from 'cli-table3'
async function delInstance (url: string) {
const [ settings, netrc ] = await Promise.all([ getSettings(), getNetrc() ])
const table = new CliTable3({
- head: ['instance', 'login'],
- colWidths: [30, 30]
- }) as CliTable3.HorizontalTable
+ head: [ 'instance', 'login' ],
+ colWidths: [ 30, 30 ]
+ }) as any
settings.remotes.forEach(element => {
if (!netrc.machines[element]) return
import { remove } from 'fs-extra'
import { sha256 } from '../helpers/core-utils'
import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl'
-import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getServerCredentials, getLogger } from './cli'
+import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getLogger, getServerCredentials } from './cli'
type UserInfo = {
username: string
.option('-T, --tmpdir <tmpdir>', 'Working directory', __dirname)
.parse(process.argv)
-let log = getLogger(program[ 'verbose' ])
+const log = getLogger(program['verbose'])
getServerCredentials(command)
.then(({ url, username, password }) => {
- if (!program[ 'targetUrl' ]) {
+ if (!program['targetUrl']) {
exitError('--target-url field is required.')
}
try {
- accessSync(program[ 'tmpdir' ], constants.R_OK | constants.W_OK)
+ accessSync(program['tmpdir'], constants.R_OK | constants.W_OK)
} catch (e) {
- exitError('--tmpdir %s: directory does not exist or is not accessible', program[ 'tmpdir' ])
+ exitError('--tmpdir %s: directory does not exist or is not accessible', program['tmpdir'])
}
url = normalizeTargetUrl(url)
- program[ 'targetUrl' ] = normalizeTargetUrl(program[ 'targetUrl' ])
+ program['targetUrl'] = normalizeTargetUrl(program['targetUrl'])
const user = { username, password }
run(url, user)
- .catch(err => {
- exitError(err)
- })
+ .catch(err => exitError(err))
})
+ .catch(err => console.error(err))
async function run (url: string, user: UserInfo) {
if (!user.password) {
const youtubeDL = await safeGetYoutubeDL()
const options = [ '-j', '--flat-playlist', '--playlist-reverse' ]
- youtubeDL.getInfo(program[ 'targetUrl' ], options, processOptions, async (err, info) => {
+ youtubeDL.getInfo(program['targetUrl'], options, processOptions, async (err, info) => {
if (err) {
exitError(err.message)
}
// Normalize utf8 fields
infoArray = [].concat(info)
- if (program[ 'first' ]) {
- infoArray = infoArray.slice(0, program[ 'first' ])
- } else if (program[ 'last' ]) {
- infoArray = infoArray.slice(-program[ 'last' ])
+ if (program['first']) {
+ infoArray = infoArray.slice(0, program['first'])
+ } else if (program['last']) {
+ infoArray = infoArray.slice(-program['last'])
}
infoArray = infoArray.map(i => normalizeObject(i))
for (const info of infoArray) {
await processVideo({
- cwd: program[ 'tmpdir' ],
+ cwd: program['tmpdir'],
url,
user,
youtubeInfo: info
})
}
- log.info('Video/s for user %s imported: %s', user.username, program[ 'targetUrl' ])
+ log.info('Video/s for user %s imported: %s', user.username, program['targetUrl'])
process.exit(0)
})
}
function processVideo (parameters: {
- cwd: string,
- url: string,
- user: { username: string, password: string },
+ cwd: string
+ url: string
+ user: { username: string, password: string }
youtubeInfo: any
}) {
const { youtubeInfo, cwd, url, user } = parameters
const videoInfo = await fetchObject(youtubeInfo)
log.debug('Fetched object.', videoInfo)
- if (program[ 'since' ]) {
- if (buildOriginallyPublishedAt(videoInfo).getTime() < program[ 'since' ].getTime()) {
+ if (program['since']) {
+ if (buildOriginallyPublishedAt(videoInfo).getTime() < program['since'].getTime()) {
log.info('Video "%s" has been published before "%s", don\'t upload it.\n',
- videoInfo.title, formatDate(program[ 'since' ]))
+ videoInfo.title, formatDate(program['since']))
return res()
}
}
- if (program[ 'until' ]) {
- if (buildOriginallyPublishedAt(videoInfo).getTime() > program[ 'until' ].getTime()) {
+ if (program['until']) {
+ if (buildOriginallyPublishedAt(videoInfo).getTime() > program['until'].getTime()) {
log.info('Video "%s" has been published after "%s", don\'t upload it.\n',
- videoInfo.title, formatDate(program[ 'until' ]))
+ videoInfo.title, formatDate(program['until']))
return res()
}
}
}
async function uploadVideoOnPeerTube (parameters: {
- videoInfo: any,
- videoPath: string,
- cwd: string,
- url: string,
- user: { username: string; password: string }
+ videoInfo: any
+ videoPath: string
+ cwd: string
+ url: string
+ user: { username: string, password: string }
}) {
const { videoInfo, videoPath, cwd, url, user } = parameters
const defaultAttributes = {
name: truncate(videoInfo.title, {
- 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max,
- 'separator': /,? +/,
- 'omission': ' […]'
+ length: CONSTRAINTS_FIELDS.VIDEOS.NAME.max,
+ separator: /,? +/,
+ omission: ' […]'
}),
category,
licence,
async function getCategory (categories: string[], url: string) {
if (!categories) return undefined
- const categoryString = categories[ 0 ]
+ const categoryString = categories[0]
if (categoryString === 'News & Politics') return 11
const categoriesServer = res.body
for (const key of Object.keys(categoriesServer)) {
- const categoryServer = categoriesServer[ key ]
+ const categoryServer = categoriesServer[key]
if (categoryString.toLowerCase() === categoryServer.toLowerCase()) return parseInt(key, 10)
}
// Deprecated key
if (key === 'resolution') continue
- const value = obj[ key ]
+ const value = obj[key]
if (typeof value === 'string') {
- newObj[ key ] = value.normalize()
+ newObj[key] = value.normalize()
} else {
- newObj[ key ] = value
+ newObj[key] = value
}
}
return new Promise<any>(async (res, rej) => {
const youtubeDL = await safeGetYoutubeDL()
- youtubeDL.getInfo(url, undefined, processOptions, async (err, videoInfo) => {
+ youtubeDL.getInfo(url, undefined, processOptions, (err, videoInfo) => {
if (err) return rej(err)
const videoInfoWithUrl = Object.assign(videoInfo, { url })
function buildUrl (info: any) {
const webpageUrl = info.webpage_url as string
- if (webpageUrl && webpageUrl.match(/^https?:\/\//)) return webpageUrl
+ if (webpageUrl?.match(/^https?:\/\//)) return webpageUrl
const url = info.url as string
- if (url && url.match(/^https?:\/\//)) return url
+ if (url?.match(/^https?:\/\//)) return url
// It seems youtube-dl does not return the video url
return 'https://www.youtube.com/watch?v=' + info.id
}
function formatDate (date: Date): string {
- return date.toISOString().split('T')[ 0 ]
+ return date.toISOString().split('T')[0]
}
function exitError (message: string, ...meta: any[]) {
+// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
+
import { registerTSPaths } from '../helpers/register-ts-paths'
registerTSPaths()
const plugins: PeerTubePlugin[] = res.body.data
const table = new CliTable3({
- head: ['name', 'version', 'homepage'],
+ head: [ 'name', 'version', 'homepage' ],
colWidths: [ 50, 10, 50 ]
- }) as CliTable3.HorizontalTable
+ }) as any
for (const plugin of plugins) {
const npmName = plugin.type === PluginType.PLUGIN
} catch (err) {
console.error('Cannot install plugin.', err)
process.exit(-1)
- return
}
console.log('Plugin installed.')
} catch (err) {
console.error('Cannot update plugin.', err)
process.exit(-1)
- return
}
console.log('Plugin updated.')
await uninstallPlugin({
url,
accessToken,
- npmName: options[ 'npmName' ]
+ npmName: options['npmName']
})
} catch (err) {
console.error('Cannot uninstall plugin.', err)
process.exit(-1)
- return
}
console.log('Plugin uninstalled.')
+// eslint-disable @typescript-eslint/no-unnecessary-type-assertion
+
import { registerTSPaths } from '../helpers/register-ts-paths'
registerTSPaths()
import { VideoRedundanciesTarget, VideoRedundancy } from '@shared/models'
import { addVideoRedundancy, listVideoRedundancies, removeVideoRedundancy } from '@shared/extra-utils/server/redundancy'
import validator from 'validator'
-import bytes = require('bytes')
import * as CliTable3 from 'cli-table3'
-import { parse } from 'url'
+import { URL } from 'url'
import { uniq } from 'lodash'
+import bytes = require('bytes')
+
program
.name('plugins')
.usage('[command] [options]')
const table = new CliTable3({
head: [ 'video id', 'video name', 'video url', 'files', 'playlists', 'by instances', 'total size' ]
- }) as CliTable3.HorizontalTable
+ }) as any
for (const redundancy of redundancies) {
const webtorrentFiles = redundancy.redundancies.files
const instances = uniq(
webtorrentFiles.concat(streamingPlaylists)
.map(r => r.fileUrl)
- .map(u => parse(u).host)
+ .map(u => new URL(u).host)
)
table.push([
const { url, username, password } = await getServerCredentials(program)
const accessToken = await getAdminTokenOrDie(url, username, password)
- if (!options[ 'video' ] || validator.isInt('' + options[ 'video' ]) === false) {
+ if (!options['video'] || validator.isInt('' + options['video']) === false) {
console.error('You need to specify the video id to duplicate and it should be a number.\n')
program.outputHelp()
process.exit(-1)
await addVideoRedundancy({
url,
accessToken,
- videoId: options[ 'video' ]
+ videoId: options['video']
})
console.log('Video will be duplicated by your instance!')
const { url, username, password } = await getServerCredentials(program)
const accessToken = await getAdminTokenOrDie(url, username, password)
- if (!options[ 'video' ] || validator.isInt('' + options[ 'video' ]) === false) {
+ if (!options['video'] || validator.isInt('' + options['video']) === false) {
console.error('You need to specify the video id to remove from your redundancies.\n')
program.outputHelp()
process.exit(-1)
}
- const videoId = parseInt(options[ 'video' ] + '', 10)
+ const videoId = parseInt(options['video'] + '', 10)
let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos')
let videoRedundancy = redundancies.find(r => videoId === r.id)
import { registerTSPaths } from '../helpers/register-ts-paths'
-registerTSPaths()
-
import * as repl from 'repl'
import * as path from 'path'
import * as _ from 'lodash'
import * as utils from '../helpers/utils'
import * as YoutubeDLUtils from '../helpers/youtube-dl'
+registerTSPaths()
+
const start = async () => {
await initDatabaseModels(true)
const initContext = (replServer) => {
return (context) => {
const properties = {
- context, repl: replServer, env: process.env,
- lodash: _, path,
- uuidv1, uuidv3, uuidv4, uuidv5,
- cli, logger, constants,
- Sequelize, sequelizeTypescript, modelsUtils,
- models: sequelizeTypescript.models, transaction: sequelizeTypescript.transaction,
- query: sequelizeTypescript.query, queryInterface: sequelizeTypescript.getQueryInterface(),
+ context,
+ repl: replServer,
+ env: process.env,
+ lodash: _,
+ path,
+ uuidv1,
+ uuidv3,
+ uuidv4,
+ uuidv5,
+ cli,
+ logger,
+ constants,
+ Sequelize,
+ sequelizeTypescript,
+ modelsUtils,
+ models: sequelizeTypescript.models,
+ transaction: sequelizeTypescript.transaction,
+ query: sequelizeTypescript.query,
+ queryInterface: sequelizeTypescript.getQueryInterface(),
YoutubeDL,
- coreUtils, ffmpegUtils, peertubeCryptoUtils, signupUtils, utils, YoutubeDLUtils
+ coreUtils,
+ ffmpegUtils,
+ peertubeCryptoUtils,
+ signupUtils,
+ utils,
+ YoutubeDLUtils
}
- for (let prop in properties) {
+ for (const prop in properties) {
Object.defineProperty(context, prop, {
configurable: false,
enumerable: true,
- value: properties[ prop ]
+ value: properties[prop]
})
}
}
getServerCredentials(command)
.then(({ url, username, password }) => {
- if (!program[ 'videoName' ] || !program[ 'file' ]) {
- if (!program[ 'videoName' ]) console.error('--video-name is required.')
- if (!program[ 'file' ]) console.error('--file is required.')
+ if (!program['videoName'] || !program['file']) {
+ if (!program['videoName']) console.error('--video-name is required.')
+ if (!program['file']) console.error('--file is required.')
process.exit(-1)
}
- if (isAbsolute(program[ 'file' ]) === false) {
+ if (isAbsolute(program['file']) === false) {
console.error('File path should be absolute.')
process.exit(-1)
}
process.exit(-1)
})
})
+ .catch(err => console.error(err))
async function run (url: string, username: string, password: string) {
const accessToken = await getAccessToken(url, username, password)
- await access(program[ 'file' ], constants.F_OK)
+ await access(program['file'], constants.F_OK)
- console.log('Uploading %s video...', program[ 'videoName' ])
+ console.log('Uploading %s video...', program['videoName'])
const videoAttributes = await buildVideoAttributesFromCommander(url, program)
Object.assign(videoAttributes, {
- fixture: program[ 'file' ],
- thumbnailfile: program[ 'thumbnail' ],
- previewfile: program[ 'preview' ]
+ fixture: program['file'],
+ thumbnailfile: program['thumbnail'],
+ previewfile: program['preview']
})
try {
await uploadVideo(url, accessToken, videoAttributes)
- console.log(`Video ${program[ 'videoName' ]} uploaded.`)
+ console.log(`Video ${program['videoName']} uploaded.`)
process.exit(0)
} catch (err) {
console.error(require('util').inspect(err))
console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
console.log()
})
- .action((url, cmd) => {
- run(url, cmd)
- .catch(err => {
- console.error(err)
- process.exit(-1)
- })
- })
+ .action((url, cmd) => run(url, cmd))
.parse(process.argv)
-async function run (url: string, program: any) {
+function run (url: string, program: any) {
if (!url) {
console.error('<url> positional argument is required.')
process.exit(-1)
#!/usr/bin/env node
+/* eslint-disable no-useless-escape */
+
import { registerTSPaths } from '../helpers/register-ts-paths'
registerTSPaths()
import * as program from 'commander'
-import {
- version,
- getSettings
-} from './cli'
+import { getSettings, version } from './cli'
program
.version(version, '-v, --version')
/* Not Yet Implemented */
program
- .command('diagnostic [action]',
- 'like couple therapy, but for your instance',
- { noHelp: true } as program.CommandOptions
- ).alias('d')
+ .command(
+ 'diagnostic [action]',
+ 'like couple therapy, but for your instance',
+ { noHelp: true } as program.CommandOptions
+ ).alias('d')
.command('admin',
- 'manage an instance where you have elevated rights',
- { noHelp: true } as program.CommandOptions
- ).alias('a')
+ 'manage an instance where you have elevated rights',
+ { noHelp: true } as program.CommandOptions
+ ).alias('a')
// help on no command
if (!process.argv.slice(2).length) {
})
.parse(process.argv)
})
+ .catch(err => console.error(err))
export type MAccountBlocklistId = Pick<AccountBlocklistModel, 'id'>
-export type MAccountBlocklistAccounts = MAccountBlocklist &
+export type MAccountBlocklistAccounts =
+ MAccountBlocklist &
Use<'ByAccount', MAccountDefault> &
Use<'BlockedAccount', MAccountDefault>
// Format for API or AP object
-export type MAccountBlocklistFormattable = Pick<MAccountBlocklist, 'createdAt'> &
+export type MAccountBlocklistFormattable =
+ Pick<MAccountBlocklist, 'createdAt'> &
Use<'ByAccount', MAccountFormattable> &
Use<'BlockedAccount', MAccountFormattable>
// ############################################################################
-export type MAccount = Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' |
+export type MAccount =
+ Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' |
'VideoComments' | 'BlockedAccounts'>
// ############################################################################
export type MAccountUrl = Use<'Actor', MActorUrl>
export type MAccountAudience = Use<'Actor', MActorAudience>
-export type MAccountIdActor = MAccountId &
+export type MAccountIdActor =
+ MAccountId &
Use<'Actor', MActor>
-export type MAccountIdActorId = MAccountId &
+export type MAccountIdActorId =
+ MAccountId &
Use<'Actor', MActorId>
// ############################################################################
// Default scope
-export type MAccountDefault = MAccount &
+export type MAccountDefault =
+ MAccount &
Use<'Actor', MActorDefault>
// Default with default association scopes
-export type MAccountDefaultChannelDefault = MAccount &
+export type MAccountDefaultChannelDefault =
+ MAccount &
Use<'Actor', MActorDefault> &
Use<'VideoChannels', MChannelDefault[]>
// We don't need some actors attributes
-export type MAccountLight = MAccount &
+export type MAccountLight =
+ MAccount &
Use<'Actor', MActorDefaultLight>
// ############################################################################
// Full actor
-export type MAccountActor = MAccount &
+export type MAccountActor =
+ MAccount &
Use<'Actor', MActor>
// Full actor with server
-export type MAccountServer = MAccount &
+export type MAccountServer =
+ MAccount &
Use<'Actor', MActorServer>
// ############################################################################
// For API
-export type MAccountSummary = FunctionProperties<MAccount> &
+export type MAccountSummary =
+ FunctionProperties<MAccount> &
Pick<MAccount, 'id' | 'name'> &
Use<'Actor', MActorSummary>
-export type MAccountSummaryBlocks = MAccountSummary &
+export type MAccountSummaryBlocks =
+ MAccountSummary &
Use<'BlockedAccounts', MAccountBlocklistId[]>
-export type MAccountAPI = MAccount &
+export type MAccountAPI =
+ MAccount &
Use<'Actor', MActorAPI>
// ############################################################################
// Format for API or AP object
-export type MAccountSummaryFormattable = FunctionProperties<MAccount> &
+export type MAccountSummaryFormattable =
+ FunctionProperties<MAccount> &
Pick<MAccount, 'id' | 'name'> &
Use<'Actor', MActorSummaryFormattable>
-export type MAccountFormattable = FunctionProperties<MAccount> &
+export type MAccountFormattable =
+ FunctionProperties<MAccount> &
Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> &
Use<'Actor', MActorFormattable>
-export type MAccountAP = Pick<MAccount, 'name' | 'description'> &
+export type MAccountAP =
+ Pick<MAccount, 'name' | 'description'> &
Use<'Actor', MActorAP>
// ############################################################################
-export type MActorFollowFollowingHost = MActorFollow &
+export type MActorFollowFollowingHost =
+ MActorFollow &
Use<'ActorFollowing', MActorUsername & MActorHost>
// ############################################################################
// With actors or actors default
-export type MActorFollowActors = MActorFollow &
+export type MActorFollowActors =
+ MActorFollow &
Use<'ActorFollower', MActor> &
Use<'ActorFollowing', MActor>
-export type MActorFollowActorsDefault = MActorFollow &
+export type MActorFollowActorsDefault =
+ MActorFollow &
Use<'ActorFollower', MActorDefault> &
Use<'ActorFollowing', MActorDefault>
-export type MActorFollowFull = MActorFollow &
+export type MActorFollowFull =
+ MActorFollow &
Use<'ActorFollower', MActorDefaultAccountChannel> &
Use<'ActorFollowing', MActorDefaultAccountChannel>
// For subscriptions
-type SubscriptionFollowing = MActorDefault &
+type SubscriptionFollowing =
+ MActorDefault &
PickWith<ActorModel, 'VideoChannel', MChannelDefault>
-export type MActorFollowActorsDefaultSubscription = MActorFollow &
+export type MActorFollowActorsDefaultSubscription =
+ MActorFollow &
Use<'ActorFollower', MActorDefault> &
Use<'ActorFollowing', SubscriptionFollowing>
-export type MActorFollowSubscriptions = MActorFollow &
+export type MActorFollowSubscriptions =
+ MActorFollow &
Use<'ActorFollowing', MActorChannelAccountActor>
// ############################################################################
// Format for API or AP object
-export type MActorFollowFormattable = Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> &
+export type MActorFollowFormattable =
+ Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> &
Use<'ActorFollower', MActorFormattable> &
Use<'ActorFollowing', MActorFormattable>
export type MActorHost = Use<'Server', MServerHost>
export type MActorRedundancyAllowedOpt = PickWithOpt<ActorModel, 'Server', MServerRedundancyAllowed>
-export type MActorDefaultLight = MActorLight &
+export type MActorDefaultLight =
+ MActorLight &
Use<'Server', MServerHost> &
Use<'Avatar', MAvatar>
-export type MActorAccountId = MActor &
+export type MActorAccountId =
+ MActor &
Use<'Account', MAccountId>
-export type MActorAccountIdActor = MActor &
+export type MActorAccountIdActor =
+ MActor &
Use<'Account', MAccountIdActor>
-export type MActorChannelId = MActor &
+export type MActorChannelId =
+ MActor &
Use<'VideoChannel', MChannelId>
-export type MActorChannelIdActor = MActor &
+export type MActorChannelIdActor =
+ MActor &
Use<'VideoChannel', MChannelIdActor>
export type MActorAccountChannelId = MActorAccountId & MActorChannelId
// Include raw account/channel/server
-export type MActorAccount = MActor &
+export type MActorAccount =
+ MActor &
Use<'Account', MAccount>
-export type MActorChannel = MActor &
+export type MActorChannel =
+ MActor &
Use<'VideoChannel', MChannel>
export type MActorDefaultAccountChannel = MActorDefault & MActorAccount & MActorChannel
-export type MActorServer = MActor &
+export type MActorServer =
+ MActor &
Use<'Server', MServer>
// ############################################################################
// Complex actor associations
-export type MActorDefault = MActor &
+export type MActorDefault =
+ MActor &
Use<'Server', MServer> &
Use<'Avatar', MAvatar>
// Actor with channel that is associated to an account and its actor
// Actor -> VideoChannel -> Account -> Actor
-export type MActorChannelAccountActor = MActor &
+export type MActorChannelAccountActor =
+ MActor &
Use<'VideoChannel', MChannelAccountActor>
-export type MActorFull = MActor &
+export type MActorFull =
+ MActor &
Use<'Server', MServer> &
Use<'Avatar', MAvatar> &
Use<'Account', MAccount> &
Use<'VideoChannel', MChannelAccountActor>
// Same than ActorFull, but the account and the channel have their actor
-export type MActorFullActor = MActor &
+export type MActorFullActor =
+ MActor &
Use<'Server', MServer> &
Use<'Avatar', MAvatar> &
Use<'Account', MAccountDefault> &
// API
-export type MActorSummary = FunctionProperties<MActor> &
+export type MActorSummary =
+ FunctionProperties<MActor> &
Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> &
Use<'Server', MServerHost> &
Use<'Avatar', MAvatar>
-export type MActorSummaryBlocks = MActorSummary &
+export type MActorSummaryBlocks =
+ MActorSummary &
Use<'Server', MServerHostBlocks>
-export type MActorAPI = Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' |
+export type MActorAPI =
+ Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' |
'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'>
// ############################################################################
// Format for API or AP object
-export type MActorSummaryFormattable = FunctionProperties<MActor> &
+export type MActorSummaryFormattable =
+ FunctionProperties<MActor> &
Pick<MActor, 'url' | 'preferredUsername'> &
Use<'Server', MServerHost> &
Use<'Avatar', MAvatarFormattable>
-export type MActorFormattable = MActorSummaryFormattable &
+export type MActorFormattable =
+ MActorSummaryFormattable &
Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> &
Use<'Server', MServerHost & Partial<Pick<MServer, 'redundancyAllowed'>>>
-export type MActorAP = MActor &
+export type MActorAP =
+ MActor &
Use<'Avatar', MAvatar>
// Format for API or AP object
-export type MAvatarFormattable = FunctionProperties<MAvatar> &
+export type MAvatarFormattable =
+ FunctionProperties<MAvatar> &
Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'>
export type MOAuthToken = Omit<OAuthTokenModel, 'User' | 'OAuthClients'>
-export type MOAuthTokenUser = MOAuthToken &
+export type MOAuthTokenUser =
+ MOAuthToken &
Use<'User', MUserAccountUrl> &
{ user?: MUserAccountUrl }
// Format for API or AP object
-export type MPluginFormattable = Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled'
+export type MPluginFormattable =
+ Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled'
| 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'>
// ############################################################################
-export type MServerBlocklistAccountServer = MServerBlocklist &
+export type MServerBlocklistAccountServer =
+ MServerBlocklist &
Use<'ByAccount', MAccountDefault> &
Use<'BlockedServer', MServer>
// Format for API or AP object
-export type MServerBlocklistFormattable = Pick<MServerBlocklist, 'createdAt'> &
+export type MServerBlocklistFormattable =
+ Pick<MServerBlocklist, 'createdAt'> &
Use<'ByAccount', MAccountFormattable> &
Use<'BlockedServer', MServerFormattable>
export type MServerHost = Pick<MServer, 'host'>
export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'>
-export type MServerHostBlocks = MServerHost &
+export type MServerHostBlocks =
+ MServerHost &
Use<'BlockedByAccounts', MAccountBlocklistId[]>
// ############################################################################
// Format for API or AP object
-export type MServerFormattable = FunctionProperties<MServer> &
+export type MServerFormattable =
+ FunctionProperties<MServer> &
Pick<MServer, 'host'>
// ############################################################################
-export namespace UserNotificationIncludes {
+export module UserNotificationIncludes {
+
export type VideoInclude = Pick<VideoModel, 'id' | 'uuid' | 'name'>
- export type VideoIncludeChannel = VideoInclude &
+ export type VideoIncludeChannel =
+ VideoInclude &
PickWith<VideoModel, 'VideoChannel', VideoChannelIncludeActor>
- export type ActorInclude = Pick<ActorModel, 'preferredUsername' | 'getHost'> &
+ export type ActorInclude =
+ Pick<ActorModel, 'preferredUsername' | 'getHost'> &
PickWith<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>> &
PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>>
export type VideoChannelInclude = Pick<VideoChannelModel, 'id' | 'name' | 'getDisplayName'>
- export type VideoChannelIncludeActor = VideoChannelInclude &
+ export type VideoChannelIncludeActor =
+ VideoChannelInclude &
PickWith<VideoChannelModel, 'Actor', ActorInclude>
export type AccountInclude = Pick<AccountModel, 'id' | 'name' | 'getDisplayName'>
- export type AccountIncludeActor = AccountInclude &
+ export type AccountIncludeActor =
+ AccountInclude &
PickWith<AccountModel, 'Actor', ActorInclude>
- export type VideoCommentInclude = Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> &
+ export type VideoCommentInclude =
+ Pick<VideoCommentModel, 'id' | 'originCommentId' | 'getThreadId'> &
PickWith<VideoCommentModel, 'Account', AccountIncludeActor> &
PickWith<VideoCommentModel, 'Video', VideoInclude>
- export type VideoAbuseInclude = Pick<VideoAbuseModel, 'id'> &
+ export type VideoAbuseInclude =
+ Pick<VideoAbuseModel, 'id'> &
PickWith<VideoAbuseModel, 'Video', VideoInclude>
- export type VideoBlacklistInclude = Pick<VideoBlacklistModel, 'id'> &
+ export type VideoBlacklistInclude =
+ Pick<VideoBlacklistModel, 'id'> &
PickWith<VideoAbuseModel, 'Video', VideoInclude>
- export type VideoImportInclude = Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> &
+ export type VideoImportInclude =
+ Pick<VideoImportModel, 'id' | 'magnetUri' | 'targetUrl' | 'torrentName'> &
PickWith<VideoImportModel, 'Video', VideoInclude>
- export type ActorFollower = Pick<ActorModel, 'preferredUsername' | 'getHost'> &
+ export type ActorFollower =
+ Pick<ActorModel, 'preferredUsername' | 'getHost'> &
PickWith<ActorModel, 'Account', AccountInclude> &
PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>> &
PickWithOpt<ActorModel, 'Avatar', Pick<AvatarModel, 'filename' | 'getStaticPath'>>
- export type ActorFollowing = Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> &
+ export type ActorFollowing =
+ Pick<ActorModel, 'preferredUsername' | 'type' | 'getHost'> &
PickWith<ActorModel, 'VideoChannel', VideoChannelInclude> &
PickWith<ActorModel, 'Account', AccountInclude> &
PickWith<ActorModel, 'Server', Pick<ServerModel, 'host'>>
- export type ActorFollowInclude = Pick<ActorFollowModel, 'id' | 'state'> &
+ export type ActorFollowInclude =
+ Pick<ActorFollowModel, 'id' | 'state'> &
PickWith<ActorFollowModel, 'ActorFollower', ActorFollower> &
PickWith<ActorFollowModel, 'ActorFollowing', ActorFollowing>
}
// ############################################################################
-export type MUserNotification = Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' |
+export type MUserNotification =
+ Omit<UserNotificationModel, 'User' | 'Video' | 'Comment' | 'VideoAbuse' | 'VideoBlacklist' |
'VideoImport' | 'Account' | 'ActorFollow'>
// ############################################################################
-export type UserNotificationModelForApi = MUserNotification &
+export type UserNotificationModelForApi =
+ MUserNotification &
Use<'Video', UserNotificationIncludes.VideoIncludeChannel> &
Use<'Comment', UserNotificationIncludes.VideoCommentInclude> &
Use<'VideoAbuse', UserNotificationIncludes.VideoAbuseInclude> &
// With account
-export type MUserAccountId = MUser &
+export type MUserAccountId =
+ MUser &
Use<'Account', MAccountId>
-export type MUserAccountUrl = MUser &
+export type MUserAccountUrl =
+ MUser &
Use<'Account', MAccountUrl & MAccountIdActorId>
-export type MUserAccount = MUser &
+export type MUserAccount =
+ MUser &
Use<'Account', MAccount>
-export type MUserAccountDefault = MUser &
+export type MUserAccountDefault =
+ MUser &
Use<'Account', MAccountDefault>
// With channel
-export type MUserNotifSettingChannelDefault = MUser &
+export type MUserNotifSettingChannelDefault =
+ MUser &
Use<'NotificationSetting', MNotificationSetting> &
Use<'Account', MAccountDefaultChannelDefault>
// With notification settings
-export type MUserWithNotificationSetting = MUser &
+export type MUserWithNotificationSetting =
+ MUser &
Use<'NotificationSetting', MNotificationSetting>
-export type MUserNotifSettingAccount = MUser &
+export type MUserNotifSettingAccount =
+ MUser &
Use<'NotificationSetting', MNotificationSetting> &
Use<'Account', MAccount>
// Default scope
-export type MUserDefault = MUser &
+export type MUserDefault =
+ MUser &
Use<'NotificationSetting', MNotificationSetting> &
Use<'Account', MAccountDefault>
// Format for API or AP object
type MAccountWithChannels = MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>
-type MAccountWithChannelsAndSpecialPlaylists = MAccountWithChannels &
+type MAccountWithChannelsAndSpecialPlaylists =
+ MAccountWithChannels &
PickWithOpt<AccountModel, 'VideoPlaylists', MVideoPlaylist[]>
-export type MUserFormattable = MUserQuotaUsed &
+export type MUserFormattable =
+ MUserQuotaUsed &
Use<'Account', MAccountWithChannels> &
PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
-export type MMyUserFormattable = MUserFormattable &
+export type MMyUserFormattable =
+ MUserFormattable &
Use<'Account', MAccountWithChannelsAndSpecialPlaylists>
// ############################################################################
-export type MScheduleVideoUpdateVideoAll = MScheduleVideoUpdate &
+export type MScheduleVideoUpdateVideoAll =
+ MScheduleVideoUpdate &
Use<'Video', MVideoAPWithoutCaption & MVideoWithBlacklistLight>
// Format for API or AP object
export type MVideoAbuseId = Pick<VideoAbuseModel, 'id'>
-export type MVideoAbuseVideo = MVideoAbuse &
+export type MVideoAbuseVideo =
+ MVideoAbuse &
Pick<VideoAbuseModel, 'toActivityPubObject'> &
Use<'Video', MVideo>
-export type MVideoAbuseAccountVideo = MVideoAbuse &
+export type MVideoAbuseAccountVideo =
+ MVideoAbuse &
Pick<VideoAbuseModel, 'toActivityPubObject'> &
Use<'Video', MVideo> &
Use<'Account', MAccountDefault>
// Format for API or AP object
-export type MVideoAbuseFormattable = MVideoAbuse &
+export type MVideoAbuseFormattable =
+ MVideoAbuse &
Use<'Account', MAccountFormattable> &
Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>>
// ############################################################################
-export type MVideoBlacklistLightVideo = MVideoBlacklistLight &
+export type MVideoBlacklistLightVideo =
+ MVideoBlacklistLight &
Use<'Video', MVideo>
-export type MVideoBlacklistVideo = MVideoBlacklist &
+export type MVideoBlacklistVideo =
+ MVideoBlacklist &
Use<'Video', MVideo>
// ############################################################################
// Format for API or AP object
-export type MVideoBlacklistFormattable = MVideoBlacklist &
+export type MVideoBlacklistFormattable =
+ MVideoBlacklist &
Use<'Video', MVideoFormattable>
export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'>
export type MVideoCaptionLanguageUrl = Pick<MVideoCaption, 'language' | 'fileUrl' | 'getFileUrl'>
-export type MVideoCaptionVideo = MVideoCaption &
+export type MVideoCaptionVideo =
+ MVideoCaption &
Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>>
// ############################################################################
// Format for API or AP object
-export type MVideoCaptionFormattable = FunctionProperties<MVideoCaption> &
+export type MVideoCaptionFormattable =
+ FunctionProperties<MVideoCaption> &
Pick<MVideoCaption, 'language'> &
Use<'Video', MVideoUUID>
export type MVideoChangeOwnership = Omit<VideoChangeOwnershipModel, 'Initiator' | 'NextOwner' | 'Video'>
-export type MVideoChangeOwnershipFull = MVideoChangeOwnership &
+export type MVideoChangeOwnershipFull =
+ MVideoChangeOwnership &
Use<'Initiator', MAccountDefault> &
Use<'NextOwner', MAccountDefault> &
Use<'Video', MVideoWithAllFiles>
// Format for API or AP object
-export type MVideoChangeOwnershipFormattable = Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> &
+export type MVideoChangeOwnershipFormattable =
+ Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> &
Use<'Initiator', MAccountFormattable> &
Use<'NextOwner', MAccountFormattable> &
Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>>
// ############################################################################
-export type MChannelIdActor = MChannelId &
+export type MChannelIdActor =
+ MChannelId &
Use<'Actor', MActorAccountChannelId>
-export type MChannelUserId = Pick<MChannel, 'accountId'> &
+export type MChannelUserId =
+ Pick<MChannel, 'accountId'> &
Use<'Account', MAccountUserId>
-export type MChannelActor = MChannel &
+export type MChannelActor =
+ MChannel &
Use<'Actor', MActor>
export type MChannelUrl = Use<'Actor', MActorUrl>
// Default scope
-export type MChannelDefault = MChannel &
+export type MChannelDefault =
+ MChannel &
Use<'Actor', MActorDefault>
// ############################################################################
// Not all association attributes
-export type MChannelLight = MChannel &
+export type MChannelLight =
+ MChannel &
Use<'Actor', MActorDefaultLight>
-export type MChannelActorLight = MChannel &
+export type MChannelActorLight =
+ MChannel &
Use<'Actor', MActorLight>
-export type MChannelAccountLight = MChannel &
+export type MChannelAccountLight =
+ MChannel &
Use<'Actor', MActorDefaultLight> &
Use<'Account', MAccountLight>
// Account associations
-export type MChannelAccountActor = MChannel &
+export type MChannelAccountActor =
+ MChannel &
Use<'Account', MAccountActor>
-export type MChannelAccountDefault = MChannel &
+export type MChannelAccountDefault =
+ MChannel &
Use<'Actor', MActorDefault> &
Use<'Account', MAccountDefault>
-export type MChannelActorAccountActor = MChannel &
+export type MChannelActorAccountActor =
+ MChannel &
Use<'Account', MAccountActor> &
Use<'Actor', MActor>
// ############################################################################
// Videos associations
-export type MChannelVideos = MChannel &
+export type MChannelVideos =
+ MChannel &
Use<'Videos', MVideo[]>
-export type MChannelActorAccountDefaultVideos = MChannel &
+export type MChannelActorAccountDefaultVideos =
+ MChannel &
Use<'Actor', MActorDefault> &
Use<'Account', MAccountDefault> &
Use<'Videos', MVideo[]>
// For API
-export type MChannelSummary = FunctionProperties<MChannel> &
+export type MChannelSummary =
+ FunctionProperties<MChannel> &
Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> &
Use<'Actor', MActorSummary>
-export type MChannelSummaryAccount = MChannelSummary &
+export type MChannelSummaryAccount =
+ MChannelSummary &
Use<'Account', MAccountSummaryBlocks>
-export type MChannelAPI = MChannel &
+export type MChannelAPI =
+ MChannel &
Use<'Actor', MActorAPI> &
Use<'Account', MAccountAPI>
// Format for API or AP object
-export type MChannelSummaryFormattable = FunctionProperties<MChannel> &
+export type MChannelSummaryFormattable =
+ FunctionProperties<MChannel> &
Pick<MChannel, 'id' | 'name'> &
Use<'Actor', MActorSummaryFormattable>
-export type MChannelAccountSummaryFormattable = MChannelSummaryFormattable &
+export type MChannelAccountSummaryFormattable =
+ MChannelSummaryFormattable &
Use<'Account', MAccountSummaryFormattable>
-export type MChannelFormattable = FunctionProperties<MChannel> &
+export type MChannelFormattable =
+ FunctionProperties<MChannel> &
Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> &
Use<'Actor', MActorFormattable> &
PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable>
-export type MChannelAP = Pick<MChannel, 'name' | 'description' | 'support'> &
+export type MChannelAP =
+ Pick<MChannel, 'name' | 'description' | 'support'> &
Use<'Actor', MActorAP> &
Use<'Account', MAccountUrl>
// ############################################################################
-export type MCommentOwner = MComment &
+export type MCommentOwner =
+ MComment &
Use<'Account', MAccountDefault>
-export type MCommentVideo = MComment &
+export type MCommentVideo =
+ MComment &
Use<'Video', MVideoAccountLight>
-export type MCommentReply = MComment &
+export type MCommentReply =
+ MComment &
Use<'InReplyToVideoComment', MComment>
-export type MCommentOwnerVideo = MComment &
+export type MCommentOwnerVideo =
+ MComment &
Use<'Account', MAccountDefault> &
Use<'Video', MVideoAccountLight>
-export type MCommentOwnerVideoReply = MComment &
+export type MCommentOwnerVideoReply =
+ MComment &
Use<'Account', MAccountDefault> &
Use<'Video', MVideoAccountLight> &
Use<'InReplyToVideoComment', MComment>
-export type MCommentOwnerReplyVideoLight = MComment &
+export type MCommentOwnerReplyVideoLight =
+ MComment &
Use<'Account', MAccountDefault> &
Use<'InReplyToVideoComment', MComment> &
Use<'Video', MVideoIdUrl>
-export type MCommentOwnerVideoFeed = MCommentOwner &
+export type MCommentOwnerVideoFeed =
+ MCommentOwner &
Use<'Video', MVideoFeed>
// ############################################################################
// Format for API or AP object
-export type MCommentFormattable = MCommentTotalReplies &
+export type MCommentFormattable =
+ MCommentTotalReplies &
Use<'Account', MAccountFormattable>
-export type MCommentAP = MComment &
+export type MCommentAP =
+ MComment &
Use<'Account', MAccountUrl> &
PickWithOpt<VideoCommentModel, 'Video', MVideoUrl> &
PickWithOpt<VideoCommentModel, 'InReplyToVideoComment', MCommentUrl>
export type MVideoFile = Omit<VideoFileModel, 'Video' | 'RedundancyVideos' | 'VideoStreamingPlaylist'>
-export type MVideoFileVideo = MVideoFile &
+export type MVideoFileVideo =
+ MVideoFile &
Use<'Video', MVideo>
-export type MVideoFileStreamingPlaylist = MVideoFile &
+export type MVideoFileStreamingPlaylist =
+ MVideoFile &
Use<'VideoStreamingPlaylist', MStreamingPlaylist>
-export type MVideoFileStreamingPlaylistVideo = MVideoFile &
+export type MVideoFileStreamingPlaylistVideo =
+ MVideoFile &
Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
-export type MVideoFileVideoUUID = MVideoFile &
+export type MVideoFileVideoUUID =
+ MVideoFile &
Use<'Video', MVideoUUID>
-export type MVideoFileRedundanciesAll = MVideoFile &
+export type MVideoFileRedundanciesAll =
+ MVideoFile &
PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancy[]>
-export type MVideoFileRedundanciesOpt = MVideoFile &
+export type MVideoFileRedundanciesOpt =
+ MVideoFile &
PickWithOpt<VideoFileModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]>
export function isStreamingPlaylistFile (file: any): file is MVideoFileStreamingPlaylist {
export type MVideoImport = Omit<VideoImportModel, 'User' | 'Video'>
-export type MVideoImportVideo = MVideoImport &
+export type MVideoImportVideo =
+ MVideoImport &
Use<'Video', MVideo>
// ############################################################################
type VideoAssociation = MVideoTag & MVideoAccountLight & MVideoThumbnail
-export type MVideoImportDefault = MVideoImport &
+export type MVideoImportDefault =
+ MVideoImport &
Use<'User', MUser> &
Use<'Video', VideoAssociation>
-export type MVideoImportDefaultFiles = MVideoImport &
+export type MVideoImportDefaultFiles =
+ MVideoImport &
Use<'User', MUser> &
Use<'Video', VideoAssociation & MVideoWithFile>
// Format for API or AP object
-export type MVideoImportFormattable = MVideoImport &
+export type MVideoImportFormattable =
+ MVideoImport &
PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag>
// ############################################################################
-export type MVideoPlaylistVideoThumbnail = MVideoPlaylistElement &
+export type MVideoPlaylistVideoThumbnail =
+ MVideoPlaylistElement &
Use<'Video', MVideoThumbnail>
-export type MVideoPlaylistElementVideoUrlPlaylistPrivacy = MVideoPlaylistElement &
+export type MVideoPlaylistElementVideoUrlPlaylistPrivacy =
+ MVideoPlaylistElement &
Use<'Video', MVideoUrl> &
Use<'VideoPlaylist', MVideoPlaylistPrivacy>
// Format for API or AP object
-export type MVideoPlaylistElementFormattable = MVideoPlaylistElement &
+export type MVideoPlaylistElementFormattable =
+ MVideoPlaylistElement &
Use<'Video', MVideoFormattable>
-export type MVideoPlaylistElementAP = MVideoPlaylistElement &
+export type MVideoPlaylistElementAP =
+ MVideoPlaylistElement &
Use<'Video', MVideoUrl>
// With elements
-export type MVideoPlaylistWithElements = MVideoPlaylist &
+export type MVideoPlaylistWithElements =
+ MVideoPlaylist &
Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
-export type MVideoPlaylistIdWithElements = MVideoPlaylistId &
+export type MVideoPlaylistIdWithElements =
+ MVideoPlaylistId &
Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
// ############################################################################
// With account
-export type MVideoPlaylistOwner = MVideoPlaylist &
+export type MVideoPlaylistOwner =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccount>
-export type MVideoPlaylistOwnerDefault = MVideoPlaylist &
+export type MVideoPlaylistOwnerDefault =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccountDefault>
// ############################################################################
// With thumbnail
-export type MVideoPlaylistThumbnail = MVideoPlaylist &
+export type MVideoPlaylistThumbnail =
+ MVideoPlaylist &
Use<'Thumbnail', MThumbnail>
-export type MVideoPlaylistAccountThumbnail = MVideoPlaylist &
+export type MVideoPlaylistAccountThumbnail =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccountDefault> &
Use<'Thumbnail', MThumbnail>
// With channel
-export type MVideoPlaylistAccountChannelDefault = MVideoPlaylist &
+export type MVideoPlaylistAccountChannelDefault =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccountDefault> &
Use<'VideoChannel', MChannelDefault>
// With all associations
-export type MVideoPlaylistFull = MVideoPlaylist &
+export type MVideoPlaylistFull =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccountDefault> &
Use<'VideoChannel', MChannelDefault> &
Use<'Thumbnail', MThumbnail>
// For API
-export type MVideoPlaylistAccountChannelSummary = MVideoPlaylist &
+export type MVideoPlaylistAccountChannelSummary =
+ MVideoPlaylist &
Use<'OwnerAccount', MAccountSummary> &
Use<'VideoChannel', MChannelSummary>
-export type MVideoPlaylistFullSummary = MVideoPlaylist &
+export type MVideoPlaylistFullSummary =
+ MVideoPlaylist &
Use<'Thumbnail', MThumbnail> &
Use<'OwnerAccount', MAccountSummary> &
Use<'VideoChannel', MChannelSummary>
// Format for API or AP object
-export type MVideoPlaylistFormattable = MVideoPlaylistVideosLength &
+export type MVideoPlaylistFormattable =
+ MVideoPlaylistVideosLength &
Use<'OwnerAccount', MAccountSummaryFormattable> &
Use<'VideoChannel', MChannelSummaryFormattable>
-export type MVideoPlaylistAP = MVideoPlaylist &
+export type MVideoPlaylistAP =
+ MVideoPlaylist &
Use<'Thumbnail', MThumbnail> &
Use<'VideoChannel', MChannelUrl>
export type MAccountVideoRate = Omit<AccountVideoRateModel, 'Video' | 'Account'>
-export type MAccountVideoRateAccountUrl = MAccountVideoRate &
+export type MAccountVideoRateAccountUrl =
+ MAccountVideoRate &
Use<'Account', MAccountUrl>
-export type MAccountVideoRateAccountVideo = MAccountVideoRate &
+export type MAccountVideoRateAccountVideo =
+ MAccountVideoRate &
Use<'Account', MAccountAudience> &
Use<'Video', MVideo>
// Format for API or AP object
-export type MAccountVideoRateFormattable = Pick<MAccountVideoRate, 'type'> &
+export type MAccountVideoRateFormattable =
+ Pick<MAccountVideoRate, 'type'> &
Use<'Video', MVideoFormattable>
// ############################################################################
-export type MVideoRedundancyFile = MVideoRedundancy &
+export type MVideoRedundancyFile =
+ MVideoRedundancy &
Use<'VideoFile', MVideoFile>
-export type MVideoRedundancyFileVideo = MVideoRedundancy &
+export type MVideoRedundancyFileVideo =
+ MVideoRedundancy &
Use<'VideoFile', MVideoFileVideo>
-export type MVideoRedundancyStreamingPlaylistVideo = MVideoRedundancy &
+export type MVideoRedundancyStreamingPlaylistVideo =
+ MVideoRedundancy &
Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
-export type MVideoRedundancyVideo = MVideoRedundancy &
+export type MVideoRedundancyVideo =
+ MVideoRedundancy &
Use<'VideoFile', MVideoFileVideo> &
Use<'VideoStreamingPlaylist', MStreamingPlaylistVideo>
// Format for API or AP object
-export type MVideoRedundancyAP = MVideoRedundancy &
+export type MVideoRedundancyAP =
+ MVideoRedundancy &
PickWithOpt<VideoRedundancyModel, 'VideoFile', MVideoFile & PickWith<VideoFileModel, 'Video', MVideoUrl>> &
PickWithOpt<VideoRedundancyModel, 'VideoStreamingPlaylist', PickWith<VideoStreamingPlaylistModel, 'Video', MVideoUrl>>
export type MVideoShare = Omit<VideoShareModel, 'Actor' | 'Video'>
-export type MVideoShareActor = MVideoShare &
+export type MVideoShareActor =
+ MVideoShare &
Use<'Actor', MActorDefault>
-export type MVideoShareFull = MVideoShare &
+export type MVideoShareFull =
+ MVideoShare &
Use<'Actor', MActorDefault> &
Use<'Video', MVideo>
export type MStreamingPlaylist = Omit<VideoStreamingPlaylistModel, 'Video' | 'RedundancyVideos' | 'VideoFiles'>
-export type MStreamingPlaylistFiles = MStreamingPlaylist &
+export type MStreamingPlaylistFiles =
+ MStreamingPlaylist &
Use<'VideoFiles', MVideoFile[]>
-export type MStreamingPlaylistVideo = MStreamingPlaylist &
+export type MStreamingPlaylistVideo =
+ MStreamingPlaylist &
Use<'Video', MVideo>
-export type MStreamingPlaylistFilesVideo = MStreamingPlaylist &
+export type MStreamingPlaylistFilesVideo =
+ MStreamingPlaylist &
Use<'VideoFiles', MVideoFile[]> &
Use<'Video', MVideo>
-export type MStreamingPlaylistRedundanciesAll = MStreamingPlaylist &
+export type MStreamingPlaylistRedundanciesAll =
+ MStreamingPlaylist &
Use<'VideoFiles', MVideoFile[]> &
Use<'RedundancyVideos', MVideoRedundancy[]>
-export type MStreamingPlaylistRedundancies = MStreamingPlaylist &
+export type MStreamingPlaylistRedundancies =
+ MStreamingPlaylist &
Use<'VideoFiles', MVideoFile[]> &
Use<'RedundancyVideos', MVideoRedundancyFileUrl[]>
-export type MStreamingPlaylistRedundanciesOpt = MStreamingPlaylist &
+export type MStreamingPlaylistRedundanciesOpt =
+ MStreamingPlaylist &
Use<'VideoFiles', MVideoFile[]> &
PickWithOpt<VideoStreamingPlaylistModel, 'RedundancyVideos', MVideoRedundancyFileUrl[]>
// ############################################################################
-export type MVideo = Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' |
+export type MVideo =
+ Omit<VideoModel, 'VideoChannel' | 'Tags' | 'Thumbnails' | 'VideoPlaylistElements' | 'VideoAbuses' |
'VideoFiles' | 'VideoStreamingPlaylists' | 'VideoShares' | 'AccountVideoRates' | 'VideoComments' | 'VideoViews' | 'UserVideoHistories' |
'ScheduleVideoUpdate' | 'VideoBlacklist' | 'VideoImport' | 'VideoCaptions'>
// Video raw associations: schedules, video files, tags, thumbnails, captions, streaming playlists
// "With" to not confuse with the VideoFile model
-export type MVideoWithFile = MVideo &
+export type MVideoWithFile =
+ MVideo &
Use<'VideoFiles', MVideoFile[]> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
-export type MVideoThumbnail = MVideo &
+export type MVideoThumbnail =
+ MVideo &
Use<'Thumbnails', MThumbnail[]>
-export type MVideoIdThumbnail = MVideoId &
+export type MVideoIdThumbnail =
+ MVideoId &
Use<'Thumbnails', MThumbnail[]>
-export type MVideoWithFileThumbnail = MVideo &
+export type MVideoWithFileThumbnail =
+ MVideo &
Use<'VideoFiles', MVideoFile[]> &
Use<'Thumbnails', MThumbnail[]>
-export type MVideoThumbnailBlacklist = MVideo &
+export type MVideoThumbnailBlacklist =
+ MVideo &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoBlacklist', MVideoBlacklistLight>
-export type MVideoTag = MVideo &
+export type MVideoTag =
+ MVideo &
Use<'Tags', MTag[]>
-export type MVideoWithSchedule = MVideo &
+export type MVideoWithSchedule =
+ MVideo &
PickWithOpt<VideoModel, 'ScheduleVideoUpdate', MScheduleVideoUpdate>
-export type MVideoWithCaptions = MVideo &
+export type MVideoWithCaptions =
+ MVideo &
Use<'VideoCaptions', MVideoCaptionLanguage[]>
-export type MVideoWithStreamingPlaylist = MVideo &
+export type MVideoWithStreamingPlaylist =
+ MVideo &
Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
// ############################################################################
// Associations with not all their attributes
-export type MVideoUserHistory = MVideo &
+export type MVideoUserHistory =
+ MVideo &
Use<'UserVideoHistories', MUserVideoHistoryTime[]>
-export type MVideoWithBlacklistLight = MVideo &
+export type MVideoWithBlacklistLight =
+ MVideo &
Use<'VideoBlacklist', MVideoBlacklistLight>
-export type MVideoAccountLight = MVideo &
+export type MVideoAccountLight =
+ MVideo &
Use<'VideoChannel', MChannelAccountLight>
-export type MVideoWithRights = MVideo &
+export type MVideoWithRights =
+ MVideo &
Use<'VideoBlacklist', MVideoBlacklistLight> &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoChannel', MChannelUserId>
// All files with some additional associations
-export type MVideoWithAllFiles = MVideo &
+export type MVideoWithAllFiles =
+ MVideo &
Use<'VideoFiles', MVideoFile[]> &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]>
-export type MVideoAccountLightBlacklistAllFiles = MVideo &
+export type MVideoAccountLightBlacklistAllFiles =
+ MVideo &
Use<'VideoFiles', MVideoFile[]> &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> &
// With account
-export type MVideoAccountDefault = MVideo &
+export type MVideoAccountDefault =
+ MVideo &
Use<'VideoChannel', MChannelAccountDefault>
-export type MVideoThumbnailAccountDefault = MVideo &
+export type MVideoThumbnailAccountDefault =
+ MVideo &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoChannel', MChannelAccountDefault>
-export type MVideoWithChannelActor = MVideo &
+export type MVideoWithChannelActor =
+ MVideo &
Use<'VideoChannel', MChannelActor>
-export type MVideoFullLight = MVideo &
+export type MVideoFullLight =
+ MVideo &
Use<'Thumbnails', MThumbnail[]> &
Use<'VideoBlacklist', MVideoBlacklistLight> &
Use<'Tags', MTag[]> &
// API
-export type MVideoAP = MVideo &
+export type MVideoAP =
+ MVideo &
Use<'Tags', MTag[]> &
Use<'VideoChannel', MChannelAccountLight> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> &
export type MVideoAPWithoutCaption = Omit<MVideoAP, 'VideoCaptions'>
-export type MVideoDetails = MVideo &
+export type MVideoDetails =
+ MVideo &
Use<'VideoBlacklist', MVideoBlacklistLight> &
Use<'Tags', MTag[]> &
Use<'VideoChannel', MChannelAccountLight> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> &
Use<'VideoFiles', MVideoFileRedundanciesOpt[]>
-export type MVideoForUser = MVideo &
+export type MVideoForUser =
+ MVideo &
Use<'VideoChannel', MChannelAccountDefault> &
Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> &
Use<'VideoBlacklist', MVideoBlacklistLight> &
Use<'Thumbnails', MThumbnail[]>
-export type MVideoForRedundancyAPI = MVideo &
+export type MVideoForRedundancyAPI =
+ MVideo &
Use<'VideoFiles', MVideoFileRedundanciesAll[]> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesAll[]>
// Format for API or AP object
-export type MVideoFormattable = MVideo &
+export type MVideoFormattable =
+ MVideo &
PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> &
Use<'VideoChannel', MChannelAccountSummaryFormattable> &
PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> &
PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>>
-export type MVideoFormattableDetails = MVideoFormattable &
+export type MVideoFormattableDetails =
+ MVideoFormattable &
Use<'VideoChannel', MChannelFormattable> &
Use<'Tags', MTag[]> &
Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundanciesOpt[]> &
+/* eslint-disable @typescript-eslint/array-type */
+
export type FunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? K : never
}[keyof T]
const l = Math.min(segmentsA.length, segmentsB.length)
for (let i = 0; i < l; i++) {
- const diff = parseInt(segmentsA[ i ], 10) - parseInt(segmentsB[ i ], 10)
+ const diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10)
if (diff) return diff
}
import * as express from 'express'
export class MockInstancesIndex {
- private indexInstances: { host: string, createdAt: string }[] = []
+ private readonly indexInstances: { host: string, createdAt: string }[] = []
initialize () {
return new Promise(res => {
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as chai from 'chai'
import { basename, dirname, isAbsolute, join, resolve } from 'path'
const expect = chai.expect
let webtorrent: WebTorrent.Instance
-function immutableAssign <T, U> (target: T, source: U) {
+function immutableAssign<T, U> (target: T, source: U) {
return Object.assign<{}, T, U>({}, target, source)
}
- // Default interval -> 5 minutes
+// Default interval -> 5 minutes
function dateIsValid (dateString: string, interval = 300000) {
const dateToCheck = new Date(dateString)
const now = new Date()
// a large file in the repo. The video needs to have a certain minimum length so
// that FFmpeg properly applies bitrate limits.
// https://stackoverflow.com/a/15795112
- return new Promise<string>(async (res, rej) => {
+ return new Promise<string>((res, rej) => {
ffmpeg()
.outputOptions([ '-f rawvideo', '-video_size 1920x1080', '-i /dev/urandom' ])
.outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
const exists = await pathExists(tempFixturePath)
if (!exists) {
- return new Promise<string>(async (res, rej) => {
+ return new Promise<string>((res, rej) => {
ffmpeg()
.outputOptions([ '-f rawvideo', '-video_size 1280x720', '-i /dev/urandom' ])
.outputOptions([ '-ac 2', '-f s16le', '-i /dev/urandom', '-t 10' ])
import { QueryTypes, Sequelize } from 'sequelize'
import { ServerInfo } from '../server/servers'
-let sequelizes: { [ id: number ]: Sequelize } = {}
+const sequelizes: { [ id: number ]: Sequelize } = {}
function getSequelize (internalServerNumber: number) {
if (sequelizes[internalServerNumber]) return sequelizes[internalServerNumber]
const seq = getSequelize(internalServerNumber)
// tslint:disable
- const query = `SELECT SUM("videoView"."views") AS "total" FROM "videoView" INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
+ const query = 'SELECT SUM("videoView"."views") AS "total" FROM "videoView" ' +
+ `INNER JOIN "video" ON "video"."id" = "videoView"."videoId" WHERE "video"."uuid" = '${uuid}'`
const options = { type: QueryTypes.SELECT as QueryTypes.SELECT }
const [ { total } ] = await seq.query<{ total: number }>(query, options)
async function closeAllSequelize (servers: ServerInfo[]) {
for (const server of servers) {
- if (sequelizes[ server.internalServerNumber ]) {
- await sequelizes[ server.internalServerNumber ].close()
- delete sequelizes[ server.internalServerNumber ]
+ if (sequelizes[server.internalServerNumber]) {
+ await sequelizes[server.internalServerNumber].close()
+ // eslint-disable-next-line
+ delete sequelizes[server.internalServerNumber]
}
}
}
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
+
import * as request from 'supertest'
import { buildAbsoluteFixturePath, root } from '../miscs/miscs'
import { isAbsolute, join } from 'path'
-import { parse } from 'url'
+import { URL } from 'url'
function get4KFileUrl () {
return 'https://download.cpy.re/peertube/4k_file.txt'
}
function makeRawRequest (url: string, statusCodeExpected?: number, range?: string) {
- const { host, protocol, pathname } = parse(url)
+ const { host, protocol, pathname } = new URL(url)
return makeGetRequest({ url: `${protocol}//${host}`, path: pathname, statusCodeExpected, range })
}
function makeGetRequest (options: {
- url: string,
- path?: string,
- query?: any,
- token?: string,
- statusCodeExpected?: number,
- contentType?: string,
+ url: string
+ path?: string
+ query?: any
+ token?: string
+ statusCodeExpected?: number
+ contentType?: string
range?: string
}) {
if (!options.statusCodeExpected) options.statusCodeExpected = 400
}
function makeDeleteRequest (options: {
- url: string,
- path: string,
- token?: string,
+ url: string
+ path: string
+ token?: string
statusCodeExpected?: number
}) {
if (!options.statusCodeExpected) options.statusCodeExpected = 400
}
function makeUploadRequest (options: {
- url: string,
- method?: 'POST' | 'PUT',
- path: string,
- token?: string,
- fields: { [ fieldName: string ]: any },
- attaches: { [ attachName: string ]: any | any[] },
+ url: string
+ method?: 'POST' | 'PUT'
+ path: string
+ token?: string
+ fields: { [ fieldName: string ]: any }
+ attaches: { [ attachName: string ]: any | any[] }
statusCodeExpected?: number
}) {
if (!options.statusCodeExpected) options.statusCodeExpected = 400
}
function makePostBodyRequest (options: {
- url: string,
- path: string,
- token?: string,
- fields?: { [ fieldName: string ]: any },
+ url: string
+ path: string
+ token?: string
+ fields?: { [ fieldName: string ]: any }
statusCodeExpected?: number
}) {
if (!options.fields) options.fields = {}
}
function makePutBodyRequest (options: {
- url: string,
- path: string,
- token?: string,
- fields: { [ fieldName: string ]: any },
+ url: string
+ path: string
+ token?: string
+ fields: { [ fieldName: string ]: any }
statusCodeExpected?: number
}) {
if (!options.statusCodeExpected) options.statusCodeExpected = 400
}
function updateAvatarRequest (options: {
- url: string,
- path: string,
- accessToken: string,
+ url: string
+ path: string
+ accessToken: string
fixture: string
}) {
let filePath = ''
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as request from 'supertest'
import { VideosSearchQuery } from '../../models/search'
import * as request from 'supertest'
-import * as urlUtil from 'url'
+import { URL } from 'url'
function getClient (url: string) {
const path = '/api/v1/oauth-clients/local'
return request(url)
.get(path)
- .set('Host', urlUtil.parse(url).host)
+ .set('Host', new URL(url).host)
.set('Accept', 'application/json')
.expect(200)
.expect('Content-Type', /json/)
import { ContactForm } from '../../models/server'
function sendContactForm (options: {
- url: string,
- fromEmail: string,
- fromName: string,
- subject: string,
- body: string,
+ url: string
+ fromEmail: string
+ fromName: string
+ subject: string
+ body: string
expectedStatus?: number
}) {
const path = '/api/v1/server/contact'
import { ActivityPubActorType, FollowState } from '@shared/models'
function getFollowersListPaginationAndSort (options: {
- url: string,
- start: number,
- count: number,
- sort: string,
- search?: string,
- actorType?: ActivityPubActorType,
+ url: string
+ start: number
+ count: number
+ sort: string
+ search?: string
+ actorType?: ActivityPubActorType
state?: FollowState
}) {
const { url, start, count, sort, search, state, actorType } = options
}
function getFollowingListPaginationAndSort (options: {
- url: string,
- start: number,
- count: number,
- sort: string,
- search?: string,
- actorType?: ActivityPubActorType,
+ url: string
+ start: number
+ count: number
+ sort: string
+ search?: string
+ actorType?: ActivityPubActorType
state?: FollowState
}) {
const { url, start, count, sort, search, state, actorType } = options
.post(path)
.set('Accept', 'application/json')
.set('Authorization', 'Bearer ' + accessToken)
- .send({ 'hosts': followingHosts })
+ .send({ hosts: followingHosts })
.expect(expectedStatus)
}
const path = '/api/v1/jobs/' + state
return request(url)
- .get(path)
- .set('Accept', 'application/json')
- .set('Authorization', 'Bearer ' + accessToken)
- .expect(200)
- .expect('Content-Type', /json/)
+ .get(path)
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + accessToken)
+ .expect(200)
+ .expect('Content-Type', /json/)
}
function getJobsListPaginationAndSort (options: {
- url: string,
- accessToken: string,
- state: JobState,
- start: number,
- count: number,
- sort: string,
+ url: string
+ accessToken: string
+ state: JobState
+ start: number
+ count: number
+ sort: string
jobType?: JobType
}) {
const { url, accessToken, state, start, count, sort, jobType } = options
import { join } from 'path'
function listPlugins (parameters: {
- url: string,
- accessToken: string,
- start?: number,
- count?: number,
- sort?: string,
- pluginType?: PluginType,
- uninstalled?: boolean,
+ url: string
+ accessToken: string
+ start?: number
+ count?: number
+ sort?: string
+ pluginType?: PluginType
+ uninstalled?: boolean
expectedStatus?: number
}) {
const { url, accessToken, start, count, sort, pluginType, uninstalled, expectedStatus = 200 } = parameters
}
function listAvailablePlugins (parameters: {
- url: string,
- accessToken: string,
- start?: number,
- count?: number,
- sort?: string,
- pluginType?: PluginType,
- currentPeerTubeEngine?: string,
+ url: string
+ accessToken: string
+ start?: number
+ count?: number
+ sort?: string
+ pluginType?: PluginType
+ currentPeerTubeEngine?: string
search?: string
expectedStatus?: number
}) {
}
function getPlugin (parameters: {
- url: string,
- accessToken: string,
- npmName: string,
+ url: string
+ accessToken: string
+ npmName: string
expectedStatus?: number
}) {
const { url, accessToken, npmName, expectedStatus = 200 } = parameters
}
function updatePluginSettings (parameters: {
- url: string,
- accessToken: string,
- npmName: string,
- settings: any,
+ url: string
+ accessToken: string
+ npmName: string
+ settings: any
expectedStatus?: number
}) {
const { url, accessToken, npmName, settings, expectedStatus = 204 } = parameters
}
function getPluginRegisteredSettings (parameters: {
- url: string,
- accessToken: string,
- npmName: string,
+ url: string
+ accessToken: string
+ npmName: string
expectedStatus?: number
}) {
const { url, accessToken, npmName, expectedStatus = 200 } = parameters
}
function getPublicSettings (parameters: {
- url: string,
- npmName: string,
+ url: string
+ npmName: string
expectedStatus?: number
}) {
const { url, npmName, expectedStatus = 200 } = parameters
}
function getPluginTranslations (parameters: {
- url: string,
- locale: string,
+ url: string
+ locale: string
expectedStatus?: number
}) {
const { url, locale, expectedStatus = 200 } = parameters
}
function installPlugin (parameters: {
- url: string,
- accessToken: string,
- path?: string,
+ url: string
+ accessToken: string
+ path?: string
npmName?: string
expectedStatus?: number
}) {
}
function updatePlugin (parameters: {
- url: string,
- accessToken: string,
- path?: string,
+ url: string
+ accessToken: string
+ path?: string
npmName?: string
expectedStatus?: number
}) {
}
function uninstallPlugin (parameters: {
- url: string,
- accessToken: string,
+ url: string
+ accessToken: string
npmName: string
expectedStatus?: number
}) {
function listVideoRedundancies (options: {
url: string
- accessToken: string,
- target: VideoRedundanciesTarget,
- start?: number,
- count?: number,
- sort?: string,
+ accessToken: string
+ target: VideoRedundanciesTarget
+ start?: number
+ count?: number
+ sort?: string
statusCodeExpected?: number
}) {
const path = '/api/v1/server/redundancy/videos'
}
function addVideoRedundancy (options: {
- url: string,
- accessToken: string,
+ url: string
+ accessToken: string
videoId: number
}) {
const path = '/api/v1/server/redundancy/videos'
}
function removeVideoRedundancy (options: {
- url: string,
- accessToken: string,
+ url: string
+ accessToken: string
redundancyId: number
}) {
const { url, accessToken, redundancyId } = options
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
import { ChildProcess, exec, fork } from 'child_process'
import { join } from 'path'
import { root, wait } from '../miscs/miscs'
import { copy, pathExists, readdir, readFile, remove } from 'fs-extra'
-import { existsSync } from 'fs'
import { expect } from 'chai'
import { VideoChannel } from '../../models/videos'
import { randomInt } from '../../core-utils/miscs/miscs'
interface ServerInfo {
- app: ChildProcess,
+ app: ChildProcess
url: string
host: string
serverNumber: number
client: {
- id: string,
+ id: string
secret: string
}
user: {
- username: string,
- password: string,
+ username: string
+ password: string
email?: string
}
}
function flushAndRunMultipleServers (totalServers: number, configOverride?: Object) {
- let apps = []
+ const apps = []
let i = 0
return new Promise<ServerInfo[]>(res => {
// Capture things if we want to
for (const key of Object.keys(regexps)) {
- const regexp = regexps[ key ]
+ const regexp = regexps[key]
const matches = data.toString().match(regexp)
if (matches !== null) {
- if (key === 'client_id') server.client.id = matches[ 1 ]
- else if (key === 'client_secret') server.client.secret = matches[ 1 ]
- else if (key === 'user_username') server.user.username = matches[ 1 ]
- else if (key === 'user_password') server.user.password = matches[ 1 ]
+ if (key === 'client_id') server.client.id = matches[1]
+ else if (key === 'client_secret') server.client.secret = matches[1]
+ else if (key === 'user_username') server.user.username = matches[1]
+ else if (key === 'user_password') server.user.password = matches[1]
}
}
// Check if all required sentences are here
for (const key of Object.keys(serverRunString)) {
- if (data.toString().indexOf(key) !== -1) serverRunString[ key ] = true
- if (serverRunString[ key ] === false) dontContinue = true
+ if (data.toString().indexOf(key) !== -1) serverRunString[key] = true
+ if (serverRunString[key] === false) dontContinue = true
}
// If no, there is maybe one thing not already initialized (client/user credentials generation...)
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import * as request from 'supertest'
import { expect } from 'chai'
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { makeGetRequest, makeDeleteRequest, makePostBodyRequest } from '../requests/requests'
const tasks: Promise<any>[] = []
for (const server of servers) {
- const p = serverLogin(server).then(t => server.accessToken = t)
+ const p = serverLogin(server).then(t => { server.accessToken = t })
tasks.push(p)
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
import { makeGetRequest, makePostBodyRequest, makePutBodyRequest } from '../requests/requests'
import { UserNotification, UserNotificationSetting, UserNotificationType } from '../../models/users'
statusCodeExpected
})
}
+
function markAsReadAllNotifications (url: string, token: string, statusCodeExpected = 204) {
const path = '/api/v1/users/me/notifications/read-all'
server: ServerInfo
emails: object[]
socketNotifications: UserNotification[]
- token: string,
+ token: string
check?: { web: boolean, mail: boolean }
}
}
function emailFinder (email: object) {
- const text = email[ 'text' ]
+ const text = email['text']
return text.indexOf(videoUUID) !== -1 && text.indexOf('Your subscription') !== -1
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes(videoUUID) && text.includes('Your video')
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
const toFind = success ? ' finished' : ' error'
return text.includes(url) && text.includes(toFind)
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes(' registered ') && text.includes(username)
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes('Your ' + followType) && text.includes(followingDisplayName) && text.includes(followerDisplayName)
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes('instance has a new follower') && text.includes(followerHost)
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes(' automatically followed a new instance') && text.includes(followingHost)
}
}
function emailFinder (email: object) {
- const text: string = email[ 'text' ]
+ const text: string = email['text']
return text.includes(' mentioned ') && text.includes(uuid) && text.includes(byAccountDisplayName)
}
}
let lastEmailCount = 0
+
async function checkNewCommentOnMyVideo (base: CheckerBaseParams, uuid: string, commentId: number, threadId: number, type: CheckerType) {
const notificationType = UserNotificationType.NEW_COMMENT_ON_MY_VIDEO
}
const commentUrl = `http://localhost:${base.server.port}/videos/watch/${uuid};threadId=${threadId}`
+
function emailFinder (email: object) {
- return email[ 'text' ].indexOf(commentUrl) !== -1
+ return email['text'].indexOf(commentUrl) !== -1
}
await checkNotification(base, notificationChecker, emailFinder, type)
}
function emailFinder (email: object) {
- const text = email[ 'text' ]
+ const text = email['text']
return text.indexOf(videoUUID) !== -1 && text.indexOf('abuse') !== -1
}
}
function emailFinder (email: object) {
- const text = email[ 'text' ]
- return text.indexOf(videoUUID) !== -1 && email[ 'text' ].indexOf('video-auto-blacklist/list') !== -1
+ const text = email['text']
+ return text.indexOf(videoUUID) !== -1 && email['text'].indexOf('video-auto-blacklist/list') !== -1
}
await checkNotification(base, notificationChecker, emailFinder, type)
}
function emailFinder (email: object) {
- const text = email[ 'text' ]
+ const text = email['text']
return text.indexOf(videoUUID) !== -1 && text.indexOf(' ' + blacklistType) !== -1
}
import { omit } from 'lodash'
type CreateUserArgs = {
- url: string,
- accessToken: string,
- username: string,
- password: string,
- videoQuota?: number,
- videoQuotaDaily?: number,
- role?: UserRole,
- adminFlags?: UserAdminFlag,
+ url: string
+ accessToken: string
+ username: string
+ password: string
+ videoQuota?: number
+ videoQuotaDaily?: number
+ role?: UserRole
+ adminFlags?: UserAdminFlag
specialStatus?: number
}
function createUser (parameters: CreateUserArgs) {
}
function registerUserWithChannel (options: {
- url: string,
- user: { username: string, password: string, displayName?: string },
+ url: string
+ user: { username: string, password: string, displayName?: string }
channel: { name: string, displayName: string }
}) {
const path = '/api/v1/users/register'
}
function updateMyAvatar (options: {
- url: string,
- accessToken: string,
+ url: string
+ accessToken: string
fixture: string
}) {
const path = '/api/v1/users/me/avatar/pick'
function updateUser (options: {
url: string
- userId: number,
- accessToken: string,
- email?: string,
- emailVerified?: boolean,
- videoQuota?: number,
- videoQuotaDaily?: number,
- password?: string,
- adminFlags?: UserAdminFlag,
+ userId: number
+ accessToken: string
+ email?: string
+ emailVerified?: boolean
+ videoQuota?: number
+ videoQuotaDaily?: number
+ password?: string
+ adminFlags?: UserAdminFlag
role?: UserRole
}) {
const path = '/api/v1/users/' + options.userId
const path = '/api/v1/videos/' + videoId + '/blacklist'
return request(url)
- .post(path)
- .send({ reason, unfederate })
- .set('Accept', 'application/json')
- .set('Authorization', 'Bearer ' + token)
- .expect(specialStatus)
+ .post(path)
+ .send({ reason, unfederate })
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
}
function updateVideoBlacklist (url: string, token: string, videoId: number, reason?: string, specialStatus = 204) {
const path = '/api/v1/videos/' + videoId + '/blacklist'
return request(url)
- .delete(path)
- .set('Accept', 'application/json')
- .set('Authorization', 'Bearer ' + token)
- .expect(specialStatus)
+ .delete(path)
+ .set('Accept', 'application/json')
+ .set('Authorization', 'Bearer ' + token)
+ .expect(specialStatus)
}
function getBlacklistedVideosList (parameters: {
- url: string,
- token: string,
- sort?: string,
- type?: VideoBlacklistType,
+ url: string
+ token: string
+ sort?: string
+ type?: VideoBlacklistType
specialStatus?: number
}) {
- let { url, token, sort, type, specialStatus = 200 } = parameters
+ const { url, token, sort, type, specialStatus = 200 } = parameters
const path = '/api/v1/videos/blacklist/'
const query = { sort, type }
const expect = chai.expect
function createVideoCaption (args: {
- url: string,
+ url: string
accessToken: string
videoId: string | number
language: string
- fixture: string,
- mimeType?: string,
+ fixture: string
+ mimeType?: string
statusCodeExpected?: number
}) {
const path = '/api/v1/videos/' + args.videoId + '/captions/' + args.language
+/* eslint-disable @typescript-eslint/no-floating-promises */
+
import * as request from 'supertest'
import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model'
import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model'
}
function getAccountVideoChannelsList (parameters: {
- url: string,
- accountName: string,
- start?: number,
- count?: number,
- sort?: string,
+ url: string
+ accountName: string
+ start?: number
+ count?: number
+ sort?: string
specialStatus?: number
}) {
const { url, accountName, start, count, sort = 'createdAt', specialStatus = 200 } = parameters
}
function updateVideoChannelAvatar (options: {
- url: string,
- accessToken: string,
- fixture: string,
+ url: string
+ accessToken: string
+ fixture: string
videoChannelName: string | number
}) {
for (const server of servers) {
const p = getMyUserInformation(server.url, server.accessToken)
- .then(res => server.videoChannel = (res.body as User).videoChannels[0])
+ .then(res => { server.videoChannel = (res.body as User).videoChannels[0] })
tasks.push(p)
}
+/* eslint-disable @typescript-eslint/no-floating-promises */
+
import * as request from 'supertest'
import { makeDeleteRequest } from '../requests/requests'
}
function getMagnetURI () {
- // tslint:disable:max-line-length
+ // eslint-disable-next-line max-len
return 'magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Ftorrents%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.torrent&xt=urn:btih:0f498834733e8057ed5c6f2ee2b4efd8d84a76ee&dn=super+peertube2+video&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fwebseed%2Fb209ca00-c8bb-4b2b-b421-1ede169f3dbc-720.mp4'
}
}
function createVideoPlaylist (options: {
- url: string,
- token: string,
- playlistAttrs: VideoPlaylistCreate,
+ url: string
+ token: string
+ playlistAttrs: VideoPlaylistCreate
expectedStatus?: number
}) {
const path = '/api/v1/video-playlists'
}
function updateVideoPlaylist (options: {
- url: string,
- token: string,
- playlistAttrs: VideoPlaylistUpdate,
- playlistId: number | string,
+ url: string
+ token: string
+ playlistAttrs: VideoPlaylistUpdate
+ playlistId: number | string
expectedStatus?: number
}) {
const path = '/api/v1/video-playlists/' + options.playlistId
}
async function addVideoInPlaylist (options: {
- url: string,
- token: string,
- playlistId: number | string,
+ url: string
+ token: string
+ playlistId: number | string
elementAttrs: VideoPlaylistElementCreate | { videoId: string }
expectedStatus?: number
}) {
}
function updateVideoPlaylistElement (options: {
- url: string,
- token: string,
- playlistId: number | string,
- playlistElementId: number | string,
- elementAttrs: VideoPlaylistElementUpdate,
+ url: string
+ token: string
+ playlistId: number | string
+ playlistElementId: number | string
+ elementAttrs: VideoPlaylistElementUpdate
expectedStatus?: number
}) {
const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
}
function removeVideoFromPlaylist (options: {
- url: string,
- token: string,
- playlistId: number | string,
- playlistElementId: number,
+ url: string
+ token: string
+ playlistId: number | string
+ playlistElementId: number
expectedStatus?: number
}) {
const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.playlistElementId
}
function reorderVideosPlaylist (options: {
- url: string,
- token: string,
- playlistId: number | string,
+ url: string
+ token: string
+ playlistId: number | string
elementAttrs: {
- startPosition: number,
- insertAfterPosition: number,
+ startPosition: number
+ insertAfterPosition: number
reorderLength?: number
- },
+ }
expectedStatus?: number
}) {
const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder'
const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
- const sha256Server = resSha.body[ videoName ][range]
+ const sha256Server = resSha.body[videoName][range]
expect(sha256(res2.body)).to.equal(sha256Server)
}
-/* tslint:disable:no-unused-expression */
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */
import { expect } from 'chai'
import { pathExists, readdir, readFile } from 'fs-extra'
description: string
publishedAt?: string
support: string
- originallyPublishedAt?: string,
+ originallyPublishedAt?: string
account: {
name: string
host: string
files: {
resolution: number
size: number
- }[],
+ }[]
thumbnailfile?: string
previewfile?: string
}
const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
- expect(file.size,
- 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')')
- .to.be.above(minSize).and.below(maxSize)
+ expect(
+ file.size,
+ 'File size for resolution ' + file.resolution.label + ' outside confidence interval (' + minSize + '> size <' + maxSize + ')'
+ ).to.be.above(minSize).and.below(maxSize)
const torrent = await webtorrentAdd(file.magnetUri, true)
expect(torrent.files).to.be.an('array')
}
async function uploadVideoAndGetId (options: {
- server: ServerInfo,
- videoName: string,
- nsfw?: boolean,
- privacy?: VideoPrivacy,
+ server: ServerInfo
+ videoName: string
+ nsfw?: boolean
+ privacy?: VideoPrivacy
token?: string
}) {
const videoAttrs: any = { name: options.videoName }
import { APObject } from './objects/object.model'
import { PlaylistObject } from './objects/playlist-object'
-export type Activity = ActivityCreate | ActivityUpdate |
- ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce |
- ActivityUndo | ActivityLike | ActivityReject | ActivityView | ActivityDislike | ActivityFlag
-
-export type ActivityType = 'Create' | 'Update' | 'Delete' | 'Follow' | 'Accept' | 'Announce' | 'Undo' | 'Like' | 'Reject' |
- 'View' | 'Dislike' | 'Flag'
+export type Activity =
+ ActivityCreate |
+ ActivityUpdate |
+ ActivityDelete |
+ ActivityFollow |
+ ActivityAccept |
+ ActivityAnnounce |
+ ActivityUndo |
+ ActivityLike |
+ ActivityReject |
+ ActivityView |
+ ActivityDislike |
+ ActivityFlag
+
+export type ActivityType =
+ 'Create' |
+ 'Update' |
+ 'Delete' |
+ 'Follow' |
+ 'Accept' |
+ 'Announce' |
+ 'Undo' |
+ 'Like' |
+ 'Reject' |
+ 'View' |
+ 'Dislike' |
+ 'Flag'
export interface ActivityAudience {
to: string[]
}
export interface ActivityUndo extends BaseActivity {
- type: 'Undo',
+ type: 'Undo'
object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce
}
export interface ActivityLike extends BaseActivity {
- type: 'Like',
+ type: 'Like'
object: APObject
}
export interface ActivityView extends BaseActivity {
- type: 'View',
+ type: 'View'
actor: string
object: APObject
}
}
export interface ActivityFlag extends BaseActivity {
- type: 'Flag',
- content: string,
+ type: 'Flag'
+ content: string
object: APObject | APObject[]
}
-import { ActivityPubAttributedTo } from './objects/common-objects'
+import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects'
export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization'
publicKeyPem: string
}
- icon: {
- type: 'Image'
- mediaType: 'image/png'
- url: string
- }
+ icon: ActivityIconObject
}
export interface ActivityPubSignature {
- type: 'GraphSignature2012'
- created: Date,
+ type: string
+ created: Date
creator: string
signatureValue: string
}
export interface CacheFileObject {
id: string
- type: 'CacheFile',
+ type: 'CacheFile'
object: string
expires: string
url: ActivityVideoUrlObject | ActivityPlaylistUrlObject
export interface ActivityIconObject {
type: 'Image'
url: string
- mediaType: 'image/jpeg'
- width: number
- height: number
+ mediaType: 'image/jpeg' | 'image/png'
+ width?: number
+ height?: number
}
export type ActivityVideoUrlObject = {
name: string
}
-export type ActivityTagObject = ActivityPlaylistSegmentHashesObject |
- ActivityPlaylistInfohashesObject |
- ActivityVideoUrlObject |
- ActivityHashTagObject |
- ActivityMentionObject |
- ActivityBitTorrentUrlObject |
- ActivityMagnetUrlObject
+export type ActivityTagObject =
+ ActivityPlaylistSegmentHashesObject
+ | ActivityPlaylistInfohashesObject
+ | ActivityVideoUrlObject
+ | ActivityHashTagObject
+ | ActivityMentionObject
+ | ActivityBitTorrentUrlObject
+ | ActivityMagnetUrlObject
-export type ActivityUrlObject = ActivityVideoUrlObject |
- ActivityPlaylistUrlObject |
- ActivityBitTorrentUrlObject |
- ActivityMagnetUrlObject |
- ActivityHtmlUrlObject
+export type ActivityUrlObject =
+ ActivityVideoUrlObject
+ | ActivityPlaylistUrlObject
+ | ActivityBitTorrentUrlObject
+ | ActivityMagnetUrlObject
+ | ActivityHtmlUrlObject
export interface ActivityPubAttributedTo {
type: 'Group' | 'Person'
export interface VideoAbuseObject {
- type: 'Flag',
+ type: 'Flag'
content: string
object: string | string[]
}
subtitleLanguage: ActivityIdentifierObject[]
views: number
sensitive: boolean
- commentsEnabled: boolean,
- downloadEnabled: boolean,
+ commentsEnabled: boolean
+ downloadEnabled: boolean
waitTranscoding: boolean
state: VideoState
published: string
export interface ViewObject {
- type: 'View',
+ type: 'View'
actor: string
object: string
}
}
export function peertubeTranslate (str: string, translations?: { [ id: string ]: string }) {
+ // FIXME: remove disable rule when the client is upgraded to typescript 3.7
+ // eslint-disable-next-line
return translations && translations[str] ? translations[str] : str
}
* The amount of users that signed in at least once in the last 30 days.
*/
activeMonth?: number
- };
+ }
/**
* The amount of posts that were made by users that are registered on this server.
*/
export interface PeertubePluginLatestVersionRequest {
- currentPeerTubeEngine?: string,
+ currentPeerTubeEngine?: string
npmNames: string[]
}
}
export type ClientScript = {
- script: string,
+ script: string
scopes: PluginClientScope[]
}
name: string
version: string
description: string
- engine: { peertube: string },
+ engine: { peertube: string }
- homepage: string,
- author: string,
- bugs: string,
- library: string,
+ homepage: string
+ author: string
+ bugs: string
+ library: string
staticDirs: { [ name: string ]: string }
css: string[]
// Fired when a user is updated by an admin/moderator
'action:api.user.updated': true,
- // Fired when a user got a new oauth2 token
+ // Fired when a user got a new oauth2 token
'action:api.user.oauth2-got-token': true
}
size: number
}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface FileRedundancyInformation extends RedundancyInformation {
}
+// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface StreamingPlaylistRedundancyInformation extends RedundancyInformation {
}
videos: {
http: {
enabled: boolean
- },
+ }
torrent: {
enabled: boolean
}
followers: {
instance: {
- enabled: boolean,
+ enabled: boolean
manualApproval: boolean
}
}
export type JobState = 'active' | 'completed' | 'failed' | 'waiting' | 'delayed'
-export type JobType = 'activitypub-http-unicast' |
- 'activitypub-http-broadcast' |
- 'activitypub-http-fetcher' |
- 'activitypub-follow' |
- 'video-file-import' |
- 'video-transcoding' |
- 'email' |
- 'video-import' |
- 'videos-views' |
- 'activitypub-refresher' |
- 'video-redundancy'
+export type JobType =
+ | 'activitypub-http-unicast'
+ | 'activitypub-http-broadcast'
+ | 'activitypub-http-fetcher'
+ | 'activitypub-follow'
+ | 'video-file-import'
+ | 'video-transcoding'
+ | 'email'
+ | 'video-import'
+ | 'videos-views'
+ | 'activitypub-refresher'
+ | 'video-redundancy'
export interface Job {
id: number
state: JobState
type: JobType
- data: any,
- error: any,
+ data: any
+ error: any
createdAt: Date | string
finishedOn: Date | string
processedOn: Date | string
}
signup: {
- allowed: boolean,
+ allowed: boolean
allowedForCurrentIP: boolean
requiresEmailVerification: boolean
}
max: number
}
extensions: string[]
- },
+ }
file: {
extensions: string[]
}
file: {
size: {
max: number
- },
+ }
extensions: string[]
}
}
import { Account } from '../actors'
import { VideoChannel } from '../videos/channel/video-channel.model'
-import { VideoPlaylist } from '../videos/playlist/video-playlist.model'
import { UserRole } from './user-role'
import { NSFWPolicyType } from '../videos/nsfw-policy.type'
import { UserNotificationSetting } from './user-notification-setting.model'
+++ /dev/null
-{
- "extends": "tslint-config-standard",
- "rules": {
- "await-promise": [true, "Bluebird"],
- "no-inferrable-types": true,
- "eofline": true,
- "indent": [true, "spaces"],
- "ter-indent": [
- true,
- 2,
- {
- "SwitchCase": 1
- }
- ],
- "max-line-length": [true, 140],
- "no-unused-variable": false, // Memory issues
- "no-floating-promises": false
- }
-}
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.1.tgz#90b68446364baf9efd8e8349bb36bd3852b75b80"
integrity sha512-aRnpPa7ysx3aNW60hTiCtLHlQaIFsXFCgQlpakNgDNVFzbtusSY8PwjAQgRWfSk0ekNoBjO51eQRB6upA9uuyw==
+"@types/eslint-visitor-keys@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d"
+ integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==
+
"@types/express-rate-limit@^3.3.0":
version "3.3.3"
resolved "https://registry.yarnpkg.com/@types/express-rate-limit/-/express-rate-limit-3.3.3.tgz#1be5c551be1615d243e3eec14dca091009c61113"
dependencies:
"@types/node" "*"
+"@types/json-schema@^7.0.3":
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
+ integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
+
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
dependencies:
"@types/node" "*"
+"@typescript-eslint/eslint-plugin@^2.18.0":
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.18.0.tgz#f8cf272dfb057ecf1ea000fea1e0b3f06a32f9cb"
+ integrity sha512-kuO8WQjV+RCZvAXVRJfXWiJ8iYEtfHlKgcqqqXg9uUkIolEHuUaMmm8/lcO4xwCOtaw6mY0gStn2Lg4/eUXXYQ==
+ dependencies:
+ "@typescript-eslint/experimental-utils" "2.18.0"
+ eslint-utils "^1.4.3"
+ functional-red-black-tree "^1.0.1"
+ regexpp "^3.0.0"
+ tsutils "^3.17.1"
+
+"@typescript-eslint/experimental-utils@2.18.0":
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.18.0.tgz#e4eab839082030282496c1439bbf9fdf2a4f3da8"
+ integrity sha512-J6MopKPHuJYmQUkANLip7g9I82ZLe1naCbxZZW3O2sIxTiq/9YYoOELEKY7oPg0hJ0V/AQ225h2z0Yp+RRMXhw==
+ dependencies:
+ "@types/json-schema" "^7.0.3"
+ "@typescript-eslint/typescript-estree" "2.18.0"
+ eslint-scope "^5.0.0"
+
+"@typescript-eslint/parser@^2.10.0":
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.18.0.tgz#d5f7fc1839abd4a985394e40e9d2454bd56aeb1f"
+ integrity sha512-SJJPxFMEYEWkM6pGfcnjLU+NJIPo+Ko1QrCBL+i0+zV30ggLD90huEmMMhKLHBpESWy9lVEeWlQibweNQzyc+A==
+ dependencies:
+ "@types/eslint-visitor-keys" "^1.0.0"
+ "@typescript-eslint/experimental-utils" "2.18.0"
+ "@typescript-eslint/typescript-estree" "2.18.0"
+ eslint-visitor-keys "^1.1.0"
+
+"@typescript-eslint/typescript-estree@2.18.0":
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.18.0.tgz#cfbd16ed1b111166617d718619c19b62764c8460"
+ integrity sha512-gVHylf7FDb8VSi2ypFuEL3hOtoC4HkZZ5dOjXvVjoyKdRrvXAOPSzpNRnKMfaUUEiSLP8UF9j9X9EDLxC0lfZg==
+ dependencies:
+ debug "^4.1.1"
+ eslint-visitor-keys "^1.1.0"
+ glob "^7.1.6"
+ is-glob "^4.0.1"
+ lodash "^4.17.15"
+ semver "^6.3.0"
+ tsutils "^3.17.1"
+
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
mime-types "~2.1.24"
negotiator "0.6.2"
+acorn-jsx@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.1.0.tgz#294adb71b57398b0680015f0a38c563ee1db5384"
+ integrity sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==
+
+acorn@^7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.0.tgz#949d36f2c292535da602283586c2477c57eb2d6c"
+ integrity sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==
+
addr-to-ip-port@^1.0.1, addr-to-ip-port@^1.4.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/addr-to-ip-port/-/addr-to-ip-port-1.5.1.tgz#bfada13fd6aeeeac19f1e9f7d84b4bbab45e5208"
resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=
-ajv@^6.5.5:
+ajv@^6.10.0, ajv@^6.10.2, ajv@^6.5.5:
version "6.11.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.11.0.tgz#c3607cbc8ae392d8a5a536f25b21f8e5f3f87fe9"
integrity sha512-nCprB/0syFYy9fVYU1ox1l2KN8S9I+tziH8D4zdZuLT3N6RMlGSGt5FSTpAiHB/Whv8Qs1cWHma1aMKZyaHRKA==
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813"
integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw==
+ansi-escapes@^4.2.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.0.tgz#a4ce2b33d6b214b7950d8595c212f12ac9cc569d"
+ integrity sha512-EiYhwo0v255HUL6eDyuLrXEkTi7WwVCLAw+SeOQ7M7qdun1z1pum4DEm/nuqIVbPvi9RPPc9k9LbyBv6H0DwVg==
+ dependencies:
+ type-fest "^0.8.1"
+
ansi-regex@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+array-includes@^3.0.3:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348"
+ integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0"
+ is-string "^1.0.5"
+
+array.prototype.flat@^1.2.1:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
+ integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
+astral-regex@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+ integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+
async-limiter@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
dependencies:
node-gyp-build "~3.7.0"
-builtin-modules@^1.1.1:
- version "1.1.1"
- resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
- integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
-
bull@^3.4.2:
version "3.12.1"
resolved "https://registry.yarnpkg.com/bull/-/bull-3.12.1.tgz#ced62d0afca81c9264b44f1b6f39243df5d2e73f"
resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA=
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
camelcase@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
pathval "^1.1.0"
type-detect "^4.0.5"
-chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2:
+chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
ansi-styles "^4.1.0"
supports-color "^7.1.0"
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+ dependencies:
+ restore-cursor "^3.1.0"
+
+cli-width@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+ integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
cliui@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
dependencies:
delayed-stream "~1.0.0"
-commander@^2.12.1, commander@^2.20.0, commander@^2.7.1:
+commander@^2.20.0, commander@^2.7.1:
version "2.20.3"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e"
integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+contains-path@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
+ integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=
+
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
shebang-command "^1.2.0"
which "^1.2.9"
+cross-spawn@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+ integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+ dependencies:
+ nice-try "^1.0.4"
+ path-key "^2.0.1"
+ semver "^5.5.0"
+ shebang-command "^1.2.0"
+ which "^1.2.9"
+
cross-spawn@^7.0.0:
version "7.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.1.tgz#0ab56286e0f7c24e153d04cc2aa027e43a9a5d14"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.9.0.tgz#d0b175a5c37ed5f17b97e2272bbc1fa5aec677d2"
integrity sha512-khbFLu/MlzLjEzy9Gh8oY1hNt/Dvxw3J6Rbc28cVoYWQaC1S3YI4xwkF9ZWcjDLscbZlY9hISMr66RFzZagLsA==
-debug@2.6.9, debug@^2.2.0:
+debug@2.6.9, debug@^2.2.0, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+deep-is@~0.1.3:
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+ integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+
deep-object-diff@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/deep-object-diff/-/deep-object-diff-1.1.0.tgz#d6fabf476c2ed1751fc94d5ca693d2ed8c18bc5a"
resolved "https://registry.yarnpkg.com/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz#73988161841f3dcc81f47686d539a2c702c88624"
integrity sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q==
-doctrine@0.7.2:
- version "0.7.2"
- resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-0.7.2.tgz#7cb860359ba3be90e040b26b729ce4bfa654c523"
- integrity sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=
+doctrine@1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
+ integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=
dependencies:
- esutils "^1.1.6"
- isarray "0.0.1"
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
dont-sniff-mimetype@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/env-variable/-/env-variable-0.0.6.tgz#74ab20b3786c545b62b4a4813ab8cf22726c9808"
integrity sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg==
-error-ex@^1.3.1:
+error-ex@^1.2.0, error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2:
+es-abstract@^1.17.0, es-abstract@^1.17.0-next.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2:
version "1.17.4"
resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+eslint-config-standard-with-typescript@^12.0.1:
+ version "12.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-12.0.1.tgz#60f941a3a942b50393715ca336e1c7ba76e3ab04"
+ integrity sha512-v0DDNzsb36Oun3N04Y27Ca9DfF+S9Orrdtqa5anUUpwIu/MMqCRxYAcKdD0Uao+Gzqz9EjaFYjBKZCPFyXH5jw==
+ dependencies:
+ "@typescript-eslint/parser" "^2.10.0"
+ eslint-config-standard "^14.1.0"
+
+eslint-config-standard@^14.1.0:
+ version "14.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.0.tgz#b23da2b76fe5a2eba668374f246454e7058f15d4"
+ integrity sha512-EF6XkrrGVbvv8hL/kYa/m6vnvmUT+K82pJJc4JJVMM6+Qgqh0pnwprSxdduDLB9p/7bIxD+YV5O0wfb8lmcPbA==
+
+eslint-import-resolver-node@^0.3.2:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
+ integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg==
+ dependencies:
+ debug "^2.6.9"
+ resolve "^1.13.1"
+
+eslint-module-utils@^2.4.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708"
+ integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==
+ dependencies:
+ debug "^2.6.9"
+ pkg-dir "^2.0.0"
+
+eslint-plugin-es@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz#98cb1bc8ab0aa807977855e11ad9d1c9422d014b"
+ integrity sha512-6/Jb/J/ZvSebydwbBJO1R9E5ky7YeElfK56Veh7e4QGFHCXoIXGH9HhVz+ibJLM3XJ1XjP+T7rKBLUa/Y7eIng==
+ dependencies:
+ eslint-utils "^2.0.0"
+ regexpp "^3.0.0"
+
+eslint-plugin-import@^2.20.1:
+ version "2.20.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3"
+ integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw==
+ dependencies:
+ array-includes "^3.0.3"
+ array.prototype.flat "^1.2.1"
+ contains-path "^0.1.0"
+ debug "^2.6.9"
+ doctrine "1.5.0"
+ eslint-import-resolver-node "^0.3.2"
+ eslint-module-utils "^2.4.1"
+ has "^1.0.3"
+ minimatch "^3.0.4"
+ object.values "^1.1.0"
+ read-pkg-up "^2.0.0"
+ resolve "^1.12.0"
+
+eslint-plugin-node@^11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.0.0.tgz#365944bb0804c5d1d501182a9bc41a0ffefed726"
+ integrity sha512-chUs/NVID+sknFiJzxoN9lM7uKSOEta8GC8365hw1nDfwIPIjjpRSwwPvQanWv8dt/pDe9EV4anmVSwdiSndNg==
+ dependencies:
+ eslint-plugin-es "^3.0.0"
+ eslint-utils "^2.0.0"
+ ignore "^5.1.1"
+ minimatch "^3.0.4"
+ resolve "^1.10.1"
+ semver "^6.1.0"
+
+eslint-plugin-promise@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
+ integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
+
+eslint-plugin-standard@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz#ff0519f7ffaff114f76d1bd7c3996eef0f6e20b4"
+ integrity sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ==
+
+eslint-scope@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9"
+ integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+eslint-utils@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f"
+ integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==
+ dependencies:
+ eslint-visitor-keys "^1.1.0"
+
+eslint-utils@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd"
+ integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA==
+ dependencies:
+ eslint-visitor-keys "^1.1.0"
+
+eslint-visitor-keys@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2"
+ integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==
+
+eslint@^6.8.0:
+ version "6.8.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb"
+ integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ ajv "^6.10.0"
+ chalk "^2.1.0"
+ cross-spawn "^6.0.5"
+ debug "^4.0.1"
+ doctrine "^3.0.0"
+ eslint-scope "^5.0.0"
+ eslint-utils "^1.4.3"
+ eslint-visitor-keys "^1.1.0"
+ espree "^6.1.2"
+ esquery "^1.0.1"
+ esutils "^2.0.2"
+ file-entry-cache "^5.0.1"
+ functional-red-black-tree "^1.0.1"
+ glob-parent "^5.0.0"
+ globals "^12.1.0"
+ ignore "^4.0.6"
+ import-fresh "^3.0.0"
+ imurmurhash "^0.1.4"
+ inquirer "^7.0.0"
+ is-glob "^4.0.0"
+ js-yaml "^3.13.1"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.3.0"
+ lodash "^4.17.14"
+ minimatch "^3.0.4"
+ mkdirp "^0.5.1"
+ natural-compare "^1.4.0"
+ optionator "^0.8.3"
+ progress "^2.0.0"
+ regexpp "^2.0.1"
+ semver "^6.1.2"
+ strip-ansi "^5.2.0"
+ strip-json-comments "^3.0.1"
+ table "^5.2.3"
+ text-table "^0.2.0"
+ v8-compile-cache "^2.0.3"
+
+espree@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.2.tgz#6c272650932b4f91c3714e5e7b5f5e2ecf47262d"
+ integrity sha512-2iUPuuPP+yW1PZaMSDM9eyVf8D5P0Hi8h83YtZ5bPc/zHYjII5khoixIUTMO794NOY8F/ThF1Bo8ncZILarUTA==
+ dependencies:
+ acorn "^7.1.0"
+ acorn-jsx "^5.1.0"
+ eslint-visitor-keys "^1.1.0"
+
esprima@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
-esutils@^1.1.6:
- version "1.1.6"
- resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.1.6.tgz#c01ccaa9ae4b897c6d0c3e210ae52f3c7a844375"
- integrity sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=
+esquery@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+ integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+ dependencies:
+ estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
esutils@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-4.0.4.tgz#a495338ae9e58c856b66d1346ec0d86f43ba2e43"
integrity sha512-DLRj2vMO7Xgai8qWKU9O6ZztF2bdDmfFNFi9k3G9BPzJ+7MG7eWaaBikbe0eBpNGSxU8JziwW0PQKG78aNWa6g==
-express-validator@^6.1.1:
- version "6.3.1"
- resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.3.1.tgz#5ad6ca3ce6141f33638608d006d26c217500f375"
- integrity sha512-YQHQKP/zlUTN6d38uWwXgK3At5phK6R24pOB/ImWisMUz/U/1AC3ZXMgiZYhtH4ViYJ6UAiV0/nj8s1Qs3kmvw==
+express-validator@^6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/express-validator/-/express-validator-6.4.0.tgz#634f96b60d53112409e270c038ab818a36f56e47"
+ integrity sha512-Fs+x0yDOSiUV+o5jIRloMyBxqpSzJiMM8KQW1IRVv2l49F6ATU0F9uPa+3K6vXNlLlhUjauv2FCGLFPMaNr24w==
dependencies:
lodash "^4.17.15"
- validator "^11.1.0"
+ validator "^12.1.0"
express@^4.12.4, express@^4.13.3, express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+fast-levenshtein@~2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
fast-safe-stringify@^2.0.4:
version "2.0.7"
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
+figures@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.1.0.tgz#4b198dd07d8d71530642864af2d45dd9e459c4ec"
+ integrity sha512-ravh8VRXqHuMvZt/d8GblBeqDMkdJMBdv/2KntFH+ra5MXkO7nxNKpzQ3n6QD/2da1kH0aWmNISdvhM7gl2gVg==
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+file-entry-cache@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+ integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+ dependencies:
+ flat-cache "^2.0.1"
+
filestream@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/filestream/-/filestream-5.0.0.tgz#79015f3bae95ad0f47ef818694846f085087b92e"
dependencies:
locate-path "^3.0.0"
+find-up@^2.0.0, find-up@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
+ integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
+ dependencies:
+ locate-path "^2.0.0"
+
find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
locate-path "^5.0.0"
path-exists "^4.0.0"
+flat-cache@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+ integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+ dependencies:
+ flatted "^2.0.0"
+ rimraf "2.6.3"
+ write "1.0.3"
+
flat@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2"
dependencies:
is-buffer "~2.0.4"
+flatted@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
+ integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
+
fluent-ffmpeg@^2.1.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fluent-ffmpeg/-/fluent-ffmpeg-2.1.2.tgz#c952de2240f812ebda0aa8006d7776ee2acf7d74"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+functional-red-black-tree@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+ integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
gauge@~2.7.3:
version "2.7.4"
resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
-glob-parent@~5.1.0:
+glob-parent@^5.0.0, glob-parent@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.3, glob@^7.1.1, glob@^7.1.3:
+glob@^7.0.3, glob@^7.1.3, glob@^7.1.6:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
ini "^1.3.4"
+globals@^12.1.0:
+ version "12.3.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-12.3.0.tgz#1e564ee5c4dded2ab098b0f88f24702a3c56be13"
+ integrity sha512-wAfjdLgFsPZsklLJvOBUBmzYE8/CwhEqSBEMRXA3qxIiNtyqvjYurAtIfDh6chlEPUfmTY3MnZh5Hfh4q0UlIw==
+ dependencies:
+ type-fest "^0.8.1"
+
got@^6.7.1:
version "6.7.1"
resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d"
integrity sha1-2WyScyB28HJxG2sQ/X1PZa2O4j0=
-iconv-lite@0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24:
+iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@~0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
minimatch "^3.0.4"
+ignore@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+ integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+ignore@^5.1.1:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
+ integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==
+
immediate-chunk-store@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/immediate-chunk-store/-/immediate-chunk-store-2.1.0.tgz#3dbd3b5cc77182526188a8da47e38488a6627336"
dependencies:
queue-microtask "^1.1.2"
+import-fresh@^3.0.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
+ integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+inquirer@^7.0.0:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.0.4.tgz#99af5bde47153abca23f5c7fc30db247f39da703"
+ integrity sha512-Bu5Td5+j11sCkqfqmUTiwv+tWisMtP0L7Q8WrqA2C/BbBhy1YTdFrvjjlrKq8oagA/tLQBski2Gcx/Sqyi2qSQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^2.4.2"
+ cli-cursor "^3.1.0"
+ cli-width "^2.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.15"
+ mute-stream "0.0.8"
+ run-async "^2.2.0"
+ rxjs "^6.5.3"
+ string-width "^4.1.0"
+ strip-ansi "^5.1.0"
+ through "^2.3.6"
+
ioredis@^4.14.1:
version "4.14.1"
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.14.1.tgz#b73ded95fcf220f106d33125a92ef6213aa31318"
resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3"
integrity sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=
-is-glob@^4.0.1, is-glob@~4.0.1:
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
dependencies:
path-is-inside "^1.0.1"
-is-promise@^2.1:
+is-promise@^2.1, is-promise@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+is-string@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6"
+ integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==
+
is-symbol@^1.0.2:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=
-isarray@~1.0.0:
+isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
dependencies:
package-json "^4.0.0"
+levn@^0.3.0, levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
libxmljs@0.19.7:
version "0.19.7"
resolved "https://registry.yarnpkg.com/libxmljs/-/libxmljs-0.19.7.tgz#96c2151b0b73f33dd29917edec82902587004e5a"
simple-get "^3.0.0"
split "^1.0.0"
+load-json-file@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8"
+ integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=
+ dependencies:
+ graceful-fs "^4.1.2"
+ parse-json "^2.2.0"
+ pify "^2.0.0"
+ strip-bom "^3.0.0"
+
+locate-path@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
+ integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=
+ dependencies:
+ p-locate "^2.0.0"
+ path-exists "^3.0.0"
+
locate-path@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
dependencies:
readable-stream "^3.4.0"
-mute-stream@~0.0.4:
+mute-stream@0.0.8, mute-stream@~0.0.4:
version "0.0.8"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508"
integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA==
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
ncp@1.0.x:
version "1.0.1"
resolved "https://registry.yarnpkg.com/ncp/-/ncp-1.0.1.tgz#d15367e5cb87432ba117d2bf80fdf45aecfb4246"
resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c"
integrity sha1-yobR/ogoFpsBICCOPchCS524NCw=
+nice-try@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+ integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
nocache@2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f"
define-properties "^1.1.3"
es-abstract "^1.17.0-next.1"
+object.values@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e"
+ integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
+
on-finished@^2.3.0, on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
dependencies:
is-wsl "^1.1.0"
+optionator@^0.8.3:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+ integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.6"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ word-wrap "~1.2.3"
+
os-homedir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561"
integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw==
+p-limit@^1.1.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
+ integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==
+ dependencies:
+ p-try "^1.0.0"
+
p-limit@^2.0.0, p-limit@^2.2.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e"
dependencies:
p-try "^2.0.0"
+p-locate@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
+ integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=
+ dependencies:
+ p-limit "^1.1.0"
+
p-locate@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
dependencies:
p-finally "^1.0.0"
+p-try@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+ integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=
+
p-try@^2.0.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74"
integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+parse-json@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+ integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+ dependencies:
+ error-ex "^1.2.0"
+
parse-json@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
-path-key@^2.0.0:
+path-key@^2.0.0, path-key@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+path-type@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"
+ integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=
+ dependencies:
+ pify "^2.0.0"
+
pathval@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0"
resolved "https://registry.yarnpkg.com/piece-length/-/piece-length-2.0.1.tgz#dbed4e78976955f34466d0a65304d0cb21914ac9"
integrity sha512-dBILiDmm43y0JPISWEmVGKBETQjwJe6mSU9GND+P9KW0SJGUwoU/odyH1nbalOP9i8WSYuqf1lQnaj92Bhw+Ug==
+pify@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+pkg-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b"
+ integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=
+ dependencies:
+ find-up "^2.1.0"
+
pkginfo@0.3.x:
version "0.3.1"
resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21"
tunnel-agent "^0.6.0"
which-pm-runs "^1.0.0"
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+
prepend-http@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+progress@^2.0.0:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+ integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
promise.prototype.finally@^3.1.1:
version "3.1.2"
resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-3.1.2.tgz#b8af89160c9c673cefe3b4c4435b53cfd0287067"
node-forge "^0.9.1"
semver "^6.3.0"
+read-pkg-up@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be"
+ integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=
+ dependencies:
+ find-up "^2.0.0"
+ read-pkg "^2.0.0"
+
+read-pkg@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8"
+ integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=
+ dependencies:
+ load-json-file "^2.0.0"
+ normalize-package-data "^2.3.2"
+ path-type "^2.0.0"
+
read-pkg@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
+regexpp@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
+ integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+
+regexpp@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.0.0.tgz#dd63982ee3300e67b41c1956f850aa680d9d330e"
+ integrity sha512-Z+hNr7RAVWxznLPuA7DIh8UNX1j9CDrUQxskw9IrBE1Dxue2lyXT+shqEIeLUjrokxIP8CMy1WkjgG3rTsd5/g==
+
registry-auth-token@^3.0.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
resolve-pkg@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9"
dependencies:
resolve-from "^2.0.0"
-resolve@^1.10.0, resolve@^1.3.2:
+resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1:
version "1.15.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
dependencies:
path-parse "^1.0.6"
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
retry-as-promised@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/retry-as-promised/-/retry-as-promised-3.2.0.tgz#769f63d536bec4783549db0777cb56dadd9d8543"
resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b"
integrity sha1-/s5hv6DBtSoga9axgZgYS91SOjs=
+rimraf@2.6.3:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+ integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+ dependencies:
+ glob "^7.1.3"
+
rimraf@2.x.x, rimraf@^2.6.1, rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
dependencies:
glob "^7.1.3"
+run-async@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+ integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+ dependencies:
+ is-promise "^2.1.0"
+
run-parallel-limit@^1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/run-parallel-limit/-/run-parallel-limit-1.0.5.tgz#c29a4fd17b4df358cb52a8a697811a63c984f1b7"
resolved "https://registry.yarnpkg.com/rusha/-/rusha-0.8.13.tgz#9a084e7b860b17bff3015b92c67a6a336191513a"
integrity sha1-mghOe4YLF7/zAVuSxnpqM2GRUTo=
-rxjs@^6.5.2:
+rxjs@^6.5.2, rxjs@^6.5.3:
version "6.5.4"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
dependencies:
semver "^5.0.3"
-"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.7.0, semver@^5.7.1:
+"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.7.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7"
integrity sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=
-semver@^6.3.0:
+semver@^6.1.0, semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
sax "^1.2.4"
xmlbuilder "^13.0.2"
+slice-ansi@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+ integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+ dependencies:
+ ansi-styles "^3.2.0"
+ astral-regex "^1.0.0"
+ is-fullwidth-code-point "^2.0.0"
+
smtp-connection@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/smtp-connection/-/smtp-connection-4.0.2.tgz#d9dd68d38569f3ad9265473670d09d8f3ea518db"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+strip-json-comments@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7"
+ integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==
+
superagent@^3.8.3:
version "3.8.3"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128"
swagger-methods "^2.0.1"
z-schema "^4.2.2"
+table@^5.2.3:
+ version "5.4.6"
+ resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e"
+ integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==
+ dependencies:
+ ajv "^6.10.2"
+ lodash "^4.17.14"
+ slice-ansi "^2.1.0"
+ string-width "^3.0.0"
+
tar-fs@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
thirty-two@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a"
readable-stream "~2.3.6"
xtend "~4.0.1"
-through@2:
+through@2, through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
es5-ext "~0.10.46"
next-tick "1"
-tmp@0.0.x:
+tmp@0.0.x, tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
minimist "^1.2.0"
strip-bom "^3.0.0"
-tslib@1.9.0:
- version "1.9.0"
- resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
- integrity sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==
-
-tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.8.1, tslib@^1.9.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
-tslint-config-standard@^9.0.0:
- version "9.0.0"
- resolved "https://registry.yarnpkg.com/tslint-config-standard/-/tslint-config-standard-9.0.0.tgz#349a94819d93d5f8d803e3c71cb58ef38eff88e0"
- integrity sha512-CAw9J743RnPMemQV/XQ4YyNreC+A1NItACfkm+cBedrOkz6CQfwlnbKn8anUXBfoa4Zo4tjAhblRbsMNcSLfSw==
- dependencies:
- tslint-eslint-rules "^5.3.1"
-
-tslint-eslint-rules@^5.3.1:
- version "5.4.0"
- resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz#e488cc9181bf193fe5cd7bfca213a7695f1737b5"
- integrity sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==
- dependencies:
- doctrine "0.7.2"
- tslib "1.9.0"
- tsutils "^3.0.0"
-
-tslint@^6.0.0:
- version "6.0.0"
- resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.0.0.tgz#1c0148beac4779924216302f192cdaa153618310"
- integrity sha512-9nLya8GBtlFmmFMW7oXXwoXS1NkrccqTqAtwXzdPV9e2mqSEvCki6iHL/Fbzi5oqbugshzgGPk7KBb2qNP1DSA==
- dependencies:
- "@babel/code-frame" "^7.0.0"
- builtin-modules "^1.1.1"
- chalk "^2.3.0"
- commander "^2.12.1"
- diff "^4.0.1"
- glob "^7.1.1"
- js-yaml "^3.13.1"
- minimatch "^3.0.4"
- mkdirp "^0.5.1"
- resolve "^1.3.2"
- semver "^5.3.0"
- tslib "^1.10.0"
- tsutils "^2.29.0"
-
-tsutils@^2.29.0:
- version "2.29.0"
- resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
- integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
- dependencies:
- tslib "^1.8.1"
-
-tsutils@^3.0.0:
+tsutils@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+ dependencies:
+ prelude-ls "~1.1.2"
+
type-detect@0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+type-fest@^0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
type-is@1.6.15:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+v8-compile-cache@^2.0.3:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
+ integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==
+
validate-npm-package-license@^3.0.1:
version "3.0.4"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
resolved "https://registry.yarnpkg.com/validator/-/validator-10.11.0.tgz#003108ea6e9a9874d31ccc9e5006856ccd76b228"
integrity sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
-validator@^11.0.0, validator@^11.1.0:
+validator@^11.0.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-11.1.0.tgz#ac18cac42e0aa5902b603d7a5d9b7827e2346ac4"
integrity sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg==
dependencies:
"@types/node" "*"
+word-wrap@~1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
+ integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==
+
wrap-ansi@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
imurmurhash "^0.1.4"
signal-exit "^3.0.2"
+write@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+ integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+ dependencies:
+ mkdirp "^0.5.1"
+
ws@^7.0.0, ws@^7.1.2:
version "7.2.1"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
-youtube-dl@^3.0.1:
- version "3.0.1"
- resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-3.0.1.tgz#c9a159824ba61c67adcb2e1b3f7b7756ae4042b1"
- integrity sha512-QsCf3CnzVPbSoXQPs78L8TIYTk6nCtcm6on3ZkhY02D+OJ3Kcup5cuZepB/TLN6TxAQuhoVK6p0tG2bmTItNVA==
+youtube-dl@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/youtube-dl/-/youtube-dl-3.0.2.tgz#66236bfbdc93127efe3a7f02894ec544b23e8aa7"
+ integrity sha512-LFFfpsYbRLpqKsnb4gzbnyN7fm190tJw3gJVSvfoEfnb/xYIPNT6i9G3jdzPDp/U5cwB3OSq63nUa7rUwxXAGA==
dependencies:
debug "~4.1.1"
execa "~3.2.0"