Move to eslint

pull/2456/head contain
Chocobozzz 2020-01-31 16:56:52 +01:00
parent a22046d166
commit a15871560f
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
390 changed files with 3950 additions and 3615 deletions

88
.eslintrc.json Normal file
View File

@ -0,0 +1,88 @@
{
"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"
]
}
}

View File

@ -63,7 +63,7 @@
"ng": "ng", "ng": "ng",
"nodemon": "nodemon", "nodemon": "nodemon",
"ts-node": "ts-node", "ts-node": "ts-node",
"tslint": "tslint", "eslint": "eslint",
"concurrently": "concurrently", "concurrently": "concurrently",
"mocha-parallel-tests": "mocha-parallel-tests", "mocha-parallel-tests": "mocha-parallel-tests",
"sasslint": "sass-lint --verbose --no-exit", "sasslint": "sass-lint --verbose --no-exit",
@ -96,7 +96,7 @@
"express": "^4.12.4", "express": "^4.12.4",
"express-oauth-server": "^2.0.0", "express-oauth-server": "^2.0.0",
"express-rate-limit": "^4.0.4", "express-rate-limit": "^4.0.4",
"express-validator": "^6.1.1", "express-validator": "^6.4.0",
"flat": "^5.0.0", "flat": "^5.0.0",
"fluent-ffmpeg": "^2.1.0", "fluent-ffmpeg": "^2.1.0",
"fs-extra": "^8.0.1", "fs-extra": "^8.0.1",
@ -139,7 +139,7 @@
"webtorrent": "^0.107.16", "webtorrent": "^0.107.16",
"winston": "3.2.1", "winston": "3.2.1",
"ws": "^7.0.0", "ws": "^7.0.0",
"youtube-dl": "^3.0.1" "youtube-dl": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@types/apicache": "^1.2.0", "@types/apicache": "^1.2.0",
@ -180,10 +180,17 @@
"@types/validator": "^12.0.1", "@types/validator": "^12.0.1",
"@types/webtorrent": "^0.107.0", "@types/webtorrent": "^0.107.0",
"@types/ws": "^7.2.1", "@types/ws": "^7.2.1",
"@typescript-eslint/eslint-plugin": "^2.18.0",
"chai": "^4.1.1", "chai": "^4.1.1",
"chai-json-schema": "^1.5.0", "chai-json-schema": "^1.5.0",
"chai-xml": "^0.3.2", "chai-xml": "^0.3.2",
"concurrently": "^5.0.0", "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", "libxmljs": "0.19.7",
"maildev": "^1.0.0-rc3", "maildev": "^1.0.0-rc3",
"marked": "^0.8.0", "marked": "^0.8.0",
@ -195,8 +202,6 @@
"supertest": "^4.0.2", "supertest": "^4.0.2",
"swagger-cli": "^3.0.1", "swagger-cli": "^3.0.1",
"ts-node": "8.6.2", "ts-node": "8.6.2",
"tslint": "^6.0.0",
"tslint-config-standard": "^9.0.0",
"typescript": "^3.7.2" "typescript": "^3.7.2"
}, },
"scripty": { "scripty": {

View File

@ -35,7 +35,7 @@ elif [ "$1" = "api-4" ]; then
npm run build:server npm run build:server
sh ./server/tests/api/ci-4.sh 2 sh ./server/tests/api/ci-4.sh 2
elif [ "$1" = "lint" ]; then 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 npm run swagger-cli -- validate support/doc/api/openapi.yaml
( cd client ( cd client

View File

@ -38,6 +38,6 @@ async function run () {
} }
await JobQueue.Instance.init() 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) console.log('Import job for video %s created.', video.uuid)
} }

View File

@ -72,7 +72,7 @@ async function run () {
await JobQueue.Instance.init() await JobQueue.Instance.init()
for (const d of dataInput) { 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) console.log('Transcoding job for video %s created.', video.uuid)
} }
} }

View File

@ -122,7 +122,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
activityPubClientRouter.get('/video-channels/:name', activityPubClientRouter.get('/video-channels/:name',
executeIfActivityPub, executeIfActivityPub,
asyncMiddleware(localVideoChannelValidator), asyncMiddleware(localVideoChannelValidator),
asyncMiddleware(videoChannelController) videoChannelController
) )
activityPubClientRouter.get('/video-channels/:name/followers', activityPubClientRouter.get('/video-channels/:name/followers',
executeIfActivityPub, executeIfActivityPub,
@ -154,7 +154,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
activityPubClientRouter.get('/video-playlists/:playlistId/:videoId', activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
executeIfActivityPub, executeIfActivityPub,
asyncMiddleware(videoPlaylistElementAPGetValidator), asyncMiddleware(videoPlaylistElementAPGetValidator),
asyncMiddleware(videoPlaylistElementController) videoPlaylistElementController
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -281,7 +281,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
return activityPubResponse(activityPubContextify(json), res) 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 const videoChannel = res.locals.videoChannel
return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res) return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
@ -353,7 +353,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
return activityPubResponse(activityPubContextify(object), 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 videoPlaylistElement = res.locals.videoPlaylistElementAP
const json = videoPlaylistElement.toActivityPubObject() const json = videoPlaylistElement.toActivityPubObject()

View File

@ -46,6 +46,10 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => {
processActivities(task.activities, options) processActivities(task.activities, options)
.then(() => cb()) .then(() => cb())
.catch(err => {
logger.error('Error in process activities.', { err })
cb()
})
}) })
function inboxController (req: express.Request, res: express.Response) { function inboxController (req: express.Request, res: express.Response) {

View File

@ -16,21 +16,17 @@ import {
accountNameWithHostGetValidator, accountNameWithHostGetValidator,
accountsSortValidator, accountsSortValidator,
ensureAuthUserOwnsAccountValidator, ensureAuthUserOwnsAccountValidator,
videosSortValidator, videoChannelsSortValidator,
videoChannelsSortValidator videosSortValidator
} from '../../middlewares/validators' } from '../../middlewares/validators'
import { AccountModel } from '../../models/account/account' import { AccountModel } from '../../models/account/account'
import { AccountVideoRateModel } from '../../models/account/account-video-rate' import { AccountVideoRateModel } from '../../models/account/account-video-rate'
import { VideoModel } from '../../models/video/video' 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 { VideoChannelModel } from '../../models/video/video-channel'
import { JobQueue } from '../../lib/job-queue' import { JobQueue } from '../../lib/job-queue'
import { logger } from '../../helpers/logger'
import { VideoPlaylistModel } from '../../models/video/video-playlist' import { VideoPlaylistModel } from '../../models/video/video-playlist'
import { import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists'
commonVideoPlaylistFiltersValidator,
videoPlaylistsSearchValidator
} from '../../middlewares/validators/videos/video-playlists'
const accountsRouter = express.Router() const accountsRouter = express.Router()
@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) {
if (account.isOutdated()) { if (account.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } }) 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()) return res.json(account.toFormattedJSON())

View File

@ -31,12 +31,12 @@ configRouter.get('/',
configRouter.get('/custom', configRouter.get('/custom',
authenticate, authenticate,
ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
asyncMiddleware(getCustomConfig) getCustomConfig
) )
configRouter.put('/custom', configRouter.put('/custom',
authenticate, authenticate,
ensureUserHasRight(UserRight.MANAGE_CONFIGURATION), ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
asyncMiddleware(customConfigUpdateValidator), customConfigUpdateValidator,
asyncMiddleware(updateCustomConfig) asyncMiddleware(updateCustomConfig)
) )
configRouter.delete('/custom', configRouter.delete('/custom',
@ -196,7 +196,7 @@ function getAbout (req: express.Request, res: express.Response) {
return res.json(about).end() 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() const data = customConfig()
return res.json(data).end() return res.json(data).end()
@ -250,7 +250,7 @@ function getRegisteredThemes () {
function getEnabledResolutions () { function getEnabledResolutions () {
return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS) 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)) .map(r => parseInt(r, 10))
} }
@ -340,13 +340,13 @@ function customConfig (): CustomConfig {
allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES, allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
threads: CONFIG.TRANSCODING.THREADS, threads: CONFIG.TRANSCODING.THREADS,
resolutions: { resolutions: {
'0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ], '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'],
'240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ], '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'],
'360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ], '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'],
'480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ], '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'],
'720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ], '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'],
'1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ], '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'],
'2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ] '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p']
}, },
webtorrent: { webtorrent: {
enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED

View File

@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) {
}) })
const total = await JobQueue.Instance.count(state) const total = await JobQueue.Instance.count(state)
const result: ResultList<any> = { const result: ResultList<Job> = {
total, total,
data: jobs.map(j => formatJob(j, state)) data: jobs.map(j => formatJob(j, state))
} }

View File

@ -24,7 +24,7 @@ export { overviewsRouter }
const buildSamples = memoizee(async function () { const buildSamples = memoizee(async function () {
const [ categories, channels, tags ] = await Promise.all([ const [ categories, channels, tags ] = await Promise.all([
VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), 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) TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
]) ])

View File

@ -1,13 +1,13 @@
import * as express from 'express' import * as express from 'express'
import { UserRight } from '../../../../shared/models/users' import { UserRight } from '../../../../shared/models/users'
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares' import { authenticate, ensureUserHasRight } from '../../../middlewares'
const debugRouter = express.Router() const debugRouter = express.Router()
debugRouter.get('/debug', debugRouter.get('/debug',
authenticate, authenticate,
ensureUserHasRight(UserRight.MANAGE_DEBUG), ensureUserHasRight(UserRight.MANAGE_DEBUG),
asyncMiddleware(getDebug) getDebug
) )
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -18,7 +18,7 @@ export {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
async function getDebug (req: express.Request, res: express.Response) { function getDebug (req: express.Request, res: express.Response) {
return res.json({ return res.json({
ip: req.ip ip: req.ip
}).end() }).end()

View File

@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) {
} }
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
.catch(err => logger.error('Cannot create follow job for %s.', host, err))
} }
return res.status(204).end() return res.status(204).end()

View File

@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) {
} }
async function generateOutput (options: { async function generateOutput (options: {
startDateQuery: string, startDateQuery: string
endDateQuery?: string, endDateQuery?: string
level: LogLevel, level: LogLevel
nameFilter: RegExp nameFilter: RegExp
}) { }) {
const { startDateQuery, level, nameFilter } = options const { startDateQuery, level, nameFilter } = options
@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
const output: any[] = [] const output: any[] = []
for (let i = lines.length - 1; i >= 0; i--) { for (let i = lines.length - 1; i >= 0; i--) {
const line = lines[ i ] const line = lines[i]
let log: any let log: any
try { try {
@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
} }
logTime = new Date(log.timestamp).getTime() 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) output.push(log)
currentSize += line.length currentSize += line.length

View File

@ -84,7 +84,7 @@ async function addVideoRedundancy (req: express.Request, res: express.Response)
videoId: res.locals.onlyVideo.id videoId: res.locals.onlyVideo.id
} }
await JobQueue.Instance.createJob({ await JobQueue.Instance.createJobWithPromise({
type: 'video-redundancy', type: 'video-redundancy',
payload payload
}) })

View File

@ -39,7 +39,7 @@ meRouter.get('/me',
) )
meRouter.delete('/me', meRouter.delete('/me',
authenticate, authenticate,
asyncMiddleware(deleteMeValidator), deleteMeValidator,
asyncMiddleware(deleteMe) asyncMiddleware(deleteMe)
) )
@ -214,7 +214,7 @@ async function updateMe (req: express.Request, res: express.Response) {
} }
async function updateMyAvatar (req: express.Request, res: express.Response) { 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 user = res.locals.oauth.token.user
const userAccount = await AccountModel.load(user.Account.id) const userAccount = await AccountModel.load(user.Account.id)

View File

@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils'
import { VideoFilter } from '../../../../shared/models/videos/video-query.type' import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
import { JobQueue } from '../../../lib/job-queue' import { JobQueue } from '../../../lib/job-queue'
import { logger } from '../../../helpers/logger'
import { sequelizeTypescript } from '../../../initializers/database' import { sequelizeTypescript } from '../../../initializers/database'
const mySubscriptionsRouter = express.Router() const mySubscriptionsRouter = express.Router()
@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions',
mySubscriptionsRouter.post('/me/subscriptions', mySubscriptionsRouter.post('/me/subscriptions',
authenticate, authenticate,
userSubscriptionAddValidator, userSubscriptionAddValidator,
asyncMiddleware(addUserSubscription) addUserSubscription
) )
mySubscriptionsRouter.get('/me/subscriptions/:uri', mySubscriptionsRouter.get('/me/subscriptions/:uri',
@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons
return res.json(existObject) 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 user = res.locals.oauth.token.User
const [ name, host ] = req.body.uri.split('@') const [ name, host ] = req.body.uri.split('@')
@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response)
} }
JobQueue.Instance.createJob({ type: 'activitypub-follow', payload }) 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() return res.status(204).end()
} }

View File

@ -119,7 +119,7 @@ async function listVideoChannels (req: express.Request, res: express.Response) {
} }
async function updateVideoChannelAvatar (req: express.Request, res: express.Response) { 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 videoChannel = res.locals.videoChannel
const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON()) const oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) {
if (videoChannelWithVideos.isOutdated()) { if (videoChannelWithVideos.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } }) 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()) return res.json(videoChannelWithVideos.toFormattedJSON())

View File

@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) {
if (videoPlaylist.isOutdated()) { if (videoPlaylist.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } }) 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()) return res.json(videoPlaylist.toFormattedJSON())

View File

@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
const buf = await readFile(torrentfile.path) const buf = await readFile(torrentfile.path)
const parsedTorrent = parseTorrent(buf) 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 { } else {
magnetUri = body.magnetUri magnetUri = body.magnetUri
const parsed = magnetUtil.decode(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 }) const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName })
@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
videoImportId: videoImport.id, videoImportId: videoImport.id,
magnetUri 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())) auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
downloadThumbnail: !thumbnailModel, downloadThumbnail: !thumbnailModel,
downloadPreview: !previewModel 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())) auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
async function processThumbnail (req: express.Request, video: VideoModel) { async function processThumbnail (req: express.Request, video: VideoModel) {
const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
if (thumbnailField) { if (thumbnailField) {
const thumbnailPhysicalFile = thumbnailField[ 0 ] const thumbnailPhysicalFile = thumbnailField[0]
return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false) return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false)
} }
@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) {
} }
function insertIntoDB (parameters: { function insertIntoDB (parameters: {
video: MVideoThumbnailAccountDefault, video: MVideoThumbnailAccountDefault
thumbnailModel: MThumbnail, thumbnailModel: MThumbnail
previewModel: MThumbnail, previewModel: MThumbnail
videoChannel: MChannelAccountDefault, videoChannel: MChannelAccountDefault
tags: string[], tags: string[]
videoImportAttributes: Partial<MVideoImport>, videoImportAttributes: Partial<MVideoImport>
user: MUser user: MUser
}): Bluebird<MVideoImportFormattable> { }): Bluebird<MVideoImportFormattable> {
const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters

View File

@ -12,8 +12,7 @@ import {
VIDEO_CATEGORIES, VIDEO_CATEGORIES,
VIDEO_LANGUAGES, VIDEO_LANGUAGES,
VIDEO_LICENCES, VIDEO_LICENCES,
VIDEO_PRIVACIES, VIDEO_PRIVACIES
VIDEO_TRANSCODING_FPS
} from '../../../initializers/constants' } from '../../../initializers/constants'
import { import {
changeVideoChannelShare, changeVideoChannelShare,
@ -308,7 +307,7 @@ async function addVideo (req: express.Request, res: express.Response) {
} }
} }
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 }) Hooks.runAction('action:api.video.uploaded', { video: videoCreated })
@ -453,7 +452,6 @@ async function getVideo (req: express.Request, res: express.Response) {
if (video.isOutdated()) { if (video.isOutdated()) {
JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) 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()) return res.json(video.toFormattedDetailsJSON())

View File

@ -66,7 +66,7 @@ export {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
async function serveServerTranslations (req: express.Request, res: express.Response) { function serveServerTranslations (req: express.Request, res: express.Response) {
const locale = req.params.locale const locale = req.params.locale
const file = req.params.file const file = req.params.file

View File

@ -45,12 +45,12 @@ staticRouter.use(
staticRouter.use( staticRouter.use(
STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent', STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent',
asyncMiddleware(videosDownloadValidator), asyncMiddleware(videosDownloadValidator),
asyncMiddleware(downloadTorrent) downloadTorrent
) )
staticRouter.use( staticRouter.use(
STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent', STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent',
asyncMiddleware(videosDownloadValidator), asyncMiddleware(videosDownloadValidator),
asyncMiddleware(downloadHLSVideoFileTorrent) downloadHLSVideoFileTorrent
) )
// Videos path for webseeding // Videos path for webseeding
@ -68,13 +68,13 @@ staticRouter.use(
staticRouter.use( staticRouter.use(
STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension', STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
asyncMiddleware(videosDownloadValidator), asyncMiddleware(videosDownloadValidator),
asyncMiddleware(downloadVideoFile) downloadVideoFile
) )
staticRouter.use( staticRouter.use(
STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension', STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
asyncMiddleware(videosDownloadValidator), asyncMiddleware(videosDownloadValidator),
asyncMiddleware(downloadHLSVideoFile) downloadHLSVideoFile
) )
// HLS // HLS
@ -325,7 +325,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
return res.send(json).end() 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 video = res.locals.videoAll
const videoFile = getVideoFile(req, video.VideoFiles) const videoFile = getVideoFile(req, video.VideoFiles)
@ -334,7 +334,7 @@ async function downloadTorrent (req: express.Request, res: express.Response) {
return res.download(getTorrentFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p.torrent`) 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 video = res.locals.videoAll
const playlist = getHLSPlaylist(video) const playlist = getHLSPlaylist(video)
@ -346,7 +346,7 @@ async function downloadHLSVideoFileTorrent (req: express.Request, res: express.R
return res.download(getTorrentFilePath(playlist, videoFile), `${video.name}-${videoFile.resolution}p-hls.torrent`) 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 video = res.locals.videoAll
const videoFile = getVideoFile(req, video.VideoFiles) const videoFile = getVideoFile(req, video.VideoFiles)
@ -355,7 +355,7 @@ async function downloadVideoFile (req: express.Request, res: express.Response) {
return res.download(getVideoFilePath(video, videoFile), `${video.name}-${videoFile.resolution}p${videoFile.extname}`) 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 video = res.locals.videoAll
const playlist = getHLSPlaylist(video) const playlist = getHLSPlaylist(video)
if (!playlist) return res.status(404).end if (!playlist) return res.status(404).end

View File

@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr'
import { Server as WebSocketServer } from 'ws' import { Server as WebSocketServer } from 'ws'
import { TRACKER_RATE_LIMITS } from '../initializers/constants' import { TRACKER_RATE_LIMITS } from '../initializers/constants'
import { VideoFileModel } from '../models/video/video-file' import { VideoFileModel } from '../models/video/video-file'
import { parse } from 'url'
import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
import { CONFIG } from '../initializers/config' import { CONFIG } from '../initializers/config'
@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({
const key = ip + '-' + infoHash const key = ip + '-' + infoHash
peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1 peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1
peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 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) { 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}`)) return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`))
} }
try { try {
@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) {
trackerServer.onWebSocketConnection(ws) trackerServer.onWebSocketConnection(ws)
}) })
server.on('upgrade', (request, socket, head) => { server.on('upgrade', (request: express.Request, socket, head) => {
const pathname = parse(request.url).pathname if (request.path === '/tracker/socket') {
if (pathname === '/tracker/socket') {
wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request)) wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request))
} }

View File

@ -5,7 +5,7 @@ import { Activity } from '../../shared/models/activitypub'
import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants' import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants'
import { signJsonLDObject } from './peertube-crypto' import { signJsonLDObject } from './peertube-crypto'
import { pageToStartAndCount } from './core-utils' import { pageToStartAndCount } from './core-utils'
import { parse } from 'url' import { URL } from 'url'
import { MActor, MVideoAccountLight } from '../typings/models' import { MActor, MVideoAccountLight } from '../typings/models'
function activityPubContextify <T> (data: T) { function activityPubContextify <T> (data: T) {
@ -161,8 +161,8 @@ function getAPId (activity: string | { id: string }) {
} }
function checkUrlsSameHost (url1: string, url2: string) { function checkUrlsSameHost (url1: string, url2: string) {
const idHost = parse(url1).host const idHost = new URL(url1).host
const actorHost = parse(url2).host const actorHost = new URL(url2).host
return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
} }

View File

@ -81,7 +81,8 @@ function auditLoggerFactory (domain: string) {
} }
abstract class EntityAuditView { 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 { toLogKeys (): object {
return chain(flatten(this.entityInfos, { delimiter: '-', safe: true })) return chain(flatten(this.entityInfos, { delimiter: '-', safe: true }))
.pick(this.keysToKeep) .pick(this.keysToKeep)
@ -121,7 +122,7 @@ const videoKeysToKeep = [
'downloadEnabled' 'downloadEnabled'
] ]
class VideoAuditView extends EntityAuditView { class VideoAuditView extends EntityAuditView {
constructor (private video: VideoDetails) { constructor (private readonly video: VideoDetails) {
super(videoKeysToKeep, 'video', video) super(videoKeysToKeep, 'video', video)
} }
} }
@ -132,7 +133,7 @@ const videoImportKeysToKeep = [
'video-name' 'video-name'
] ]
class VideoImportAuditView extends EntityAuditView { class VideoImportAuditView extends EntityAuditView {
constructor (private videoImport: VideoImport) { constructor (private readonly videoImport: VideoImport) {
super(videoImportKeysToKeep, 'video-import', videoImport) super(videoImportKeysToKeep, 'video-import', videoImport)
} }
} }
@ -151,7 +152,7 @@ const commentKeysToKeep = [
'account-name' 'account-name'
] ]
class CommentAuditView extends EntityAuditView { class CommentAuditView extends EntityAuditView {
constructor (private comment: VideoComment) { constructor (private readonly comment: VideoComment) {
super(commentKeysToKeep, 'comment', comment) super(commentKeysToKeep, 'comment', comment)
} }
} }
@ -180,7 +181,7 @@ const userKeysToKeep = [
'videoChannels' 'videoChannels'
] ]
class UserAuditView extends EntityAuditView { class UserAuditView extends EntityAuditView {
constructor (private user: User) { constructor (private readonly user: User) {
super(userKeysToKeep, 'user', user) super(userKeysToKeep, 'user', user)
} }
} }
@ -206,7 +207,7 @@ const channelKeysToKeep = [
'ownerAccount-displayedName' 'ownerAccount-displayedName'
] ]
class VideoChannelAuditView extends EntityAuditView { class VideoChannelAuditView extends EntityAuditView {
constructor (private channel: VideoChannel) { constructor (private readonly channel: VideoChannel) {
super(channelKeysToKeep, 'channel', channel) super(channelKeysToKeep, 'channel', channel)
} }
} }
@ -221,7 +222,7 @@ const videoAbuseKeysToKeep = [
'createdAt' 'createdAt'
] ]
class VideoAbuseAuditView extends EntityAuditView { class VideoAbuseAuditView extends EntityAuditView {
constructor (private videoAbuse: VideoAbuse) { constructor (private readonly videoAbuse: VideoAbuse) {
super(videoAbuseKeysToKeep, 'abuse', videoAbuse) super(videoAbuseKeysToKeep, 'abuse', videoAbuse)
} }
} }
@ -253,9 +254,12 @@ class CustomConfigAuditView extends EntityAuditView {
const infos: any = customConfig const infos: any = customConfig
const resolutionsDict = infos.transcoding.resolutions const resolutionsDict = infos.transcoding.resolutions
const resolutionsArray = [] const resolutionsArray = []
Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => {
Object.entries(resolutionsDict)
.forEach(([ resolution, isEnabled ]) => {
if (isEnabled) resolutionsArray.push(resolution) if (isEnabled) resolutionsArray.push(resolution)
}) })
Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } }) Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } })
super(customConfigKeysToKeep, 'config', infos) super(customConfigKeysToKeep, 'config', infos)
} }

View File

@ -1,9 +1,11 @@
/* eslint-disable no-useless-call */
/* /*
Different from 'utils' because we don't not import other PeerTube modules. Different from 'utils' because we don't not import other PeerTube modules.
Useful to avoid circular dependencies. 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 { basename, isAbsolute, join, resolve } from 'path'
import * as pem from 'pem' import * as pem from 'pem'
import { URL } from 'url' import { URL } from 'url'
@ -22,7 +24,7 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va
const newObject = {} const newObject = {}
Object.keys(oldObject).forEach(oldKey => { Object.keys(oldObject).forEach(oldKey => {
const newKey = keyConverter(oldKey) const newKey = keyConverter(oldKey)
newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter) newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter)
}) })
return newObject return newObject
@ -42,11 +44,11 @@ export function parseDurationToMs (duration: number | string): number {
if (typeof duration === 'number') return duration if (typeof duration === 'number') return duration
if (typeof duration === 'string') { if (typeof duration === 'string') {
const split = duration.match(/^([\d\.,]+)\s?(\w+)$/) const split = duration.match(/^([\d.,]+)\s?(\w+)$/)
if (split.length === 3) { if (split.length === 3) {
const len = parseFloat(split[1]) const len = parseFloat(split[1])
let unit = split[2].replace(/s$/i,'').toLowerCase() let unit = split[2].replace(/s$/i, '').toLowerCase()
if (unit === 'm') { if (unit === 'm') {
unit = 'ms' unit = 'ms'
} }
@ -73,21 +75,21 @@ export function parseBytes (value: string | number): number {
if (value.match(tgm)) { if (value.match(tgm)) {
match = value.match(tgm) match = value.match(tgm)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 * 1024 parseInt(match[2], 10) * 1024 * 1024 * 1024 +
+ parseInt(match[3], 10) * 1024 * 1024 parseInt(match[3], 10) * 1024 * 1024
} else if (value.match(tg)) { } else if (value.match(tg)) {
match = value.match(tg) match = value.match(tg)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 * 1024 parseInt(match[2], 10) * 1024 * 1024 * 1024
} else if (value.match(tm)) { } else if (value.match(tm)) {
match = value.match(tm) match = value.match(tm)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 parseInt(match[2], 10) * 1024 * 1024
} else if (value.match(gm)) { } else if (value.match(gm)) {
match = value.match(gm) match = value.match(gm)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 return parseInt(match[1], 10) * 1024 * 1024 * 1024 +
+ parseInt(match[2], 10) * 1024 * 1024 parseInt(match[2], 10) * 1024 * 1024
} else if (value.match(t)) { } else if (value.match(t)) {
match = value.match(t) match = value.match(t)
return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
@ -137,6 +139,7 @@ function getAppNumber () {
} }
let rootPath: string let rootPath: string
function root () { function root () {
if (rootPath) return rootPath if (rootPath) return rootPath
@ -163,7 +166,7 @@ function escapeHTML (stringParam) {
'=': '&#x3D;' '=': '&#x3D;'
} }
return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s]) return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
} }
function pageToStartAndCount (page: number, itemsPerPage: number) { function pageToStartAndCount (page: number, itemsPerPage: number) {
@ -202,6 +205,7 @@ function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex')
function execShell (command: string, options?: ExecOptions) { function execShell (command: string, options?: ExecOptions) {
return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => {
exec(command, options, (err, stdout, stderr) => { exec(command, options, (err, stdout, stderr) => {
// eslint-disable-next-line prefer-promise-reject-errors
if (err) return rej({ err, stdout, stderr }) if (err) return rej({ err, stdout, stderr })
return res({ stdout, stderr }) return res({ stdout, stderr })
@ -226,14 +230,6 @@ function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) =>
} }
} }
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> { 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 function promisified (arg1: T, arg2: U): Promise<A> {
return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
@ -242,15 +238,7 @@ function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A)
} }
} }
function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> { const randomBytesPromise = promisify1<number, Buffer>(randomBytes)
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 createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
const execPromise2 = promisify2<string, any, string>(exec) const execPromise2 = promisify2<string, any, string>(exec)
@ -280,7 +268,7 @@ export {
promisify1, promisify1,
promisify2, promisify2,
pseudoRandomBytesPromise, randomBytesPromise,
createPrivateKey, createPrivateKey,
getPublicKey, getPublicKey,
execPromise2, execPromise2,

View File

@ -5,52 +5,52 @@ import { logger } from './logger'
const CACHE = { const CACHE = {
'https://w3id.org/security/v1': { 'https://w3id.org/security/v1': {
'@context': { '@context': {
'id': '@id', id: '@id',
'type': '@type', type: '@type',
'dc': 'http://purl.org/dc/terms/', dc: 'http://purl.org/dc/terms/',
'sec': 'https://w3id.org/security#', sec: 'https://w3id.org/security#',
'xsd': 'http://www.w3.org/2001/XMLSchema#', xsd: 'http://www.w3.org/2001/XMLSchema#',
'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016', EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016',
'Ed25519Signature2018': 'sec:Ed25519Signature2018', Ed25519Signature2018: 'sec:Ed25519Signature2018',
'EncryptedMessage': 'sec:EncryptedMessage', EncryptedMessage: 'sec:EncryptedMessage',
'GraphSignature2012': 'sec:GraphSignature2012', GraphSignature2012: 'sec:GraphSignature2012',
'LinkedDataSignature2015': 'sec:LinkedDataSignature2015', LinkedDataSignature2015: 'sec:LinkedDataSignature2015',
'LinkedDataSignature2016': 'sec:LinkedDataSignature2016', LinkedDataSignature2016: 'sec:LinkedDataSignature2016',
'CryptographicKey': 'sec:Key', CryptographicKey: 'sec:Key',
'authenticationTag': 'sec:authenticationTag', authenticationTag: 'sec:authenticationTag',
'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm', canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm',
'cipherAlgorithm': 'sec:cipherAlgorithm', cipherAlgorithm: 'sec:cipherAlgorithm',
'cipherData': 'sec:cipherData', cipherData: 'sec:cipherData',
'cipherKey': 'sec:cipherKey', cipherKey: 'sec:cipherKey',
'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' }, created: { '@id': 'dc:created', '@type': 'xsd:dateTime' },
'creator': { '@id': 'dc:creator', '@type': '@id' }, creator: { '@id': 'dc:creator', '@type': '@id' },
'digestAlgorithm': 'sec:digestAlgorithm', digestAlgorithm: 'sec:digestAlgorithm',
'digestValue': 'sec:digestValue', digestValue: 'sec:digestValue',
'domain': 'sec:domain', domain: 'sec:domain',
'encryptionKey': 'sec:encryptionKey', encryptionKey: 'sec:encryptionKey',
'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' }, expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
'initializationVector': 'sec:initializationVector', initializationVector: 'sec:initializationVector',
'iterationCount': 'sec:iterationCount', iterationCount: 'sec:iterationCount',
'nonce': 'sec:nonce', nonce: 'sec:nonce',
'normalizationAlgorithm': 'sec:normalizationAlgorithm', normalizationAlgorithm: 'sec:normalizationAlgorithm',
'owner': { '@id': 'sec:owner', '@type': '@id' }, owner: { '@id': 'sec:owner', '@type': '@id' },
'password': 'sec:password', password: 'sec:password',
'privateKey': { '@id': 'sec:privateKey', '@type': '@id' }, privateKey: { '@id': 'sec:privateKey', '@type': '@id' },
'privateKeyPem': 'sec:privateKeyPem', privateKeyPem: 'sec:privateKeyPem',
'publicKey': { '@id': 'sec:publicKey', '@type': '@id' }, publicKey: { '@id': 'sec:publicKey', '@type': '@id' },
'publicKeyBase58': 'sec:publicKeyBase58', publicKeyBase58: 'sec:publicKeyBase58',
'publicKeyPem': 'sec:publicKeyPem', publicKeyPem: 'sec:publicKeyPem',
'publicKeyWif': 'sec:publicKeyWif', publicKeyWif: 'sec:publicKeyWif',
'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' }, publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' },
'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' }, revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
'salt': 'sec:salt', salt: 'sec:salt',
'signature': 'sec:signature', signature: 'sec:signature',
'signatureAlgorithm': 'sec:signingAlgorithm', signatureAlgorithm: 'sec:signingAlgorithm',
'signatureValue': 'sec:signatureValue' signatureValue: 'sec:signatureValue'
} }
} }
} }
@ -60,12 +60,12 @@ const nodeDocumentLoader = jsonld.documentLoaders.node()
const lru = new AsyncLRU({ const lru = new AsyncLRU({
max: 10, max: 10,
load: (url, cb) => { load: (url, cb) => {
if (CACHE[ url ] !== undefined) { if (CACHE[url] !== undefined) {
logger.debug('Using cache for JSON-LD %s.', url) logger.debug('Using cache for JSON-LD %s.', url)
return cb(null, { return cb(null, {
contextUrl: null, contextUrl: null,
document: CACHE[ url ], document: CACHE[url],
documentUrl: url documentUrl: url
}) })
} }

View File

@ -6,7 +6,7 @@ import { isHostValid } from '../servers'
import { peertubeTruncate } from '@server/helpers/core-utils' import { peertubeTruncate } from '@server/helpers/core-utils'
function isActorEndpointsObjectValid (endpointObject: any) { function isActorEndpointsObjectValid (endpointObject: any) {
if (endpointObject && endpointObject.sharedInbox) { if (endpointObject?.sharedInbox) {
return isActivityPubUrlValid(endpointObject.sharedInbox) return isActivityPubUrlValid(endpointObject.sharedInbox)
} }
@ -101,8 +101,6 @@ function normalizeActor (actor: any) {
actor.summary = null actor.summary = null
} }
} }
return
} }
function isValidActorHandle (handle: string) { function isValidActorHandle (handle: string) {

View File

@ -48,8 +48,6 @@ function normalizeComment (comment: any) {
if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
else comment.url = comment.id else comment.url = comment.id
} }
return
} }
function isCommentTypeValid (comment: any): boolean { function isCommentTypeValid (comment: any): boolean {

View File

@ -94,13 +94,13 @@ function isFileValid (
if (isArray(files)) return optional if (isArray(files)) return optional
// Should have a file // Should have a file
const fileArray = files[ field ] const fileArray = files[field]
if (!fileArray || fileArray.length === 0) { if (!fileArray || fileArray.length === 0) {
return optional return optional
} }
// The file should exist // The file should exist
const file = fileArray[ 0 ] const file = fileArray[0]
if (!file || !file.originalname) return false if (!file || !file.originalname) return false
// Check size // Check size

View File

@ -14,7 +14,7 @@ function isPluginTypeValid (value: any) {
function isPluginNameValid (value: string) { function isPluginNameValid (value: string) {
return exists(value) && return exists(value) &&
validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) && validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) &&
validator.matches(value, /^[a-z\-]+$/) validator.matches(value, /^[a-z-]+$/)
} }
function isNpmPluginNameValid (value: string) { function isNpmPluginNameValid (value: string) {
@ -146,8 +146,8 @@ function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginT
} }
function isLibraryCodeValid (library: any) { function isLibraryCodeValid (library: any) {
return typeof library.register === 'function' return typeof library.register === 'function' &&
&& typeof library.unregister === 'function' typeof library.unregister === 'function'
} }
export { export {

View File

@ -9,7 +9,8 @@ function isUserNotificationTypeValid (value: any) {
function isUserNotificationSettingValid (value: any) { function isUserNotificationSettingValid (value: any) {
return exists(value) && return exists(value) &&
validator.isInt('' + value) && ( validator.isInt('' + value) &&
(
value === UserNotificationSettingValue.NONE || value === UserNotificationSettingValue.NONE ||
value === UserNotificationSettingValue.WEB || value === UserNotificationSettingValue.WEB ||
value === UserNotificationSettingValue.EMAIL || value === UserNotificationSettingValue.EMAIL ||

View File

@ -1,8 +1,6 @@
import { Response } from 'express'
import validator from 'validator' import validator from 'validator'
import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
import { exists } from './misc' import { exists } from './misc'
import { VideoAbuseModel } from '../../models/video/video-abuse'
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
@ -15,7 +13,7 @@ function isVideoAbuseModerationCommentValid (value: string) {
} }
function isVideoAbuseStateValid (value: string) { function isVideoAbuseStateValid (value: string) {
return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -2,7 +2,7 @@ import { CONSTRAINTS_FIELDS, MIMETYPES, VIDEO_LANGUAGES } from '../../initialize
import { exists, isFileValid } from './misc' import { exists, isFileValid } from './misc'
function isVideoCaptionLanguageValid (value: any) { 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) const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT)

View File

@ -20,7 +20,7 @@ function isVideoImportTargetUrlValid (url: string) {
} }
function isVideoImportStateValid (value: any) { 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})`) const videoTorrentImportTypes = Object.keys(MIMETYPES.TORRENT.MIMETYPE_EXT).map(m => `(${m})`)

View File

@ -1,8 +1,6 @@
import { exists } from './misc' import { exists } from './misc'
import validator from 'validator' import validator from 'validator'
import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants' 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 const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS
@ -15,7 +13,7 @@ function isVideoPlaylistDescriptionValid (value: any) {
} }
function isVideoPlaylistPrivacyValid (value: number) { 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 isVideoPlaylistTimestampValid (value: any) {
@ -23,7 +21,7 @@ function isVideoPlaylistTimestampValid (value: any) {
} }
function isVideoPlaylistTypeValid (value: any) { function isVideoPlaylistTypeValid (value: any) {
return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -20,15 +20,15 @@ function isVideoFilterValid (filter: VideoFilter) {
} }
function isVideoCategoryValid (value: any) { function isVideoCategoryValid (value: any) {
return value === null || VIDEO_CATEGORIES[ value ] !== undefined return value === null || VIDEO_CATEGORIES[value] !== undefined
} }
function isVideoStateValid (value: any) { function isVideoStateValid (value: any) {
return exists(value) && VIDEO_STATES[ value ] !== undefined return exists(value) && VIDEO_STATES[value] !== undefined
} }
function isVideoLicenceValid (value: any) { function isVideoLicenceValid (value: any) {
return value === null || VIDEO_LICENCES[ value ] !== undefined return value === null || VIDEO_LICENCES[value] !== undefined
} }
function isVideoLanguageValid (value: any) { function isVideoLanguageValid (value: any) {
@ -98,7 +98,7 @@ function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } |
} }
function isVideoPrivacyValid (value: number) { function isVideoPrivacyValid (value: number) {
return VIDEO_PRIVACIES[ value ] !== undefined return VIDEO_PRIVACIES[value] !== undefined
} }
function isScheduleVideoUpdatePrivacyValid (value: number) { function isScheduleVideoUpdatePrivacyValid (value: number) {

View File

@ -12,7 +12,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
if (paramNSFW === 'false') return false if (paramNSFW === 'false') return false
if (paramNSFW === 'both') return undefined if (paramNSFW === 'both') return undefined
if (res && res.locals.oauth) { if (res?.locals.oauth) {
const user = res.locals.oauth.token.User const user = res.locals.oauth.token.User
// User does not want NSFW videos // User does not want NSFW videos
@ -28,7 +28,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
return null 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 const files = req.files
if (!files) return if (!files) return
@ -39,7 +39,7 @@ function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.
} }
for (const key of Object.keys(files)) { for (const key of Object.keys(files)) {
const file = files[ key ] const file = files[key]
if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
else deleteFileAsync(file.path) else deleteFileAsync(file.path)
@ -65,18 +65,18 @@ function badRequest (req: express.Request, res: express.Response) {
function createReqFiles ( function createReqFiles (
fieldNames: string[], fieldNames: string[],
mimeTypes: { [ id: string ]: string }, mimeTypes: { [id: string]: string },
destinations: { [ fieldName: string ]: string } destinations: { [fieldName: string]: string }
) { ) {
const storage = multer.diskStorage({ const storage = multer.diskStorage({
destination: (req, file, cb) => { destination: (req, file, cb) => {
cb(null, destinations[ file.fieldname ]) cb(null, destinations[file.fieldname])
}, },
filename: async (req, file, cb) => { filename: async (req, file, cb) => {
let extension: string let extension: string
const fileExtension = extname(file.originalname) 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 // 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 // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
@ -99,7 +99,7 @@ function createReqFiles (
} }
}) })
let fields: { name: string, maxCount: number }[] = [] const fields: { name: string, maxCount: number }[] = []
for (const fieldName of fieldNames) { for (const fieldName of fieldNames) {
fields.push({ fields.push({
name: fieldName, name: fieldName,

View File

@ -1,6 +1,6 @@
import * as ffmpeg from 'fluent-ffmpeg' import * as ffmpeg from 'fluent-ffmpeg'
import { dirname, join } from 'path' 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 { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
import { processImage } from './image-utils' import { processImage } from './image-utils'
import { logger } from './logger' import { logger } from './logger'
@ -8,6 +8,71 @@ import { checkFFmpegEncoders } from '../initializers/checker-before-init'
import { readFile, remove, writeFile } from 'fs-extra' import { readFile, remove, writeFile } from 'fs-extra'
import { CONFIG } from '../initializers/config' 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) { function computeResolutionsToTranscode (videoFileHeight: number) {
const resolutionsEnabled: number[] = [] const resolutionsEnabled: number[] = []
const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
@ -24,7 +89,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
] ]
for (const resolution of resolutions) { for (const resolution of resolutions) {
if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) {
resolutionsEnabled.push(resolution) resolutionsEnabled.push(resolution)
} }
} }
@ -48,9 +113,9 @@ async function getVideoStreamCodec (path: string) {
const videoCodec = videoStream.codec_tag_string const videoCodec = videoStream.codec_tag_string
const baseProfileMatrix = { const baseProfileMatrix = {
'High': '6400', High: '6400',
'Main': '4D40', Main: '4D40',
'Baseline': '42E0' Baseline: '42E0'
} }
let baseProfile = baseProfileMatrix[videoStream.profile] let baseProfile = baseProfileMatrix[videoStream.profile]
@ -91,7 +156,7 @@ async function getVideoFileFPS (path: string) {
if (videoStream === null) return 0 if (videoStream === null) return 0
for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) { for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
const valuesText: string = videoStream[ key ] const valuesText: string = videoStream[key]
if (!valuesText) continue if (!valuesText) continue
const [ frames, seconds ] = valuesText.split('/') const [ frames, seconds ] = valuesText.split('/')
@ -191,7 +256,8 @@ interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions {
type: 'only-audio' type: 'only-audio'
} }
type TranscodeOptions = HLSTranscodeOptions type TranscodeOptions =
HLSTranscodeOptions
| VideoTranscodeOptions | VideoTranscodeOptions
| MergeAudioTranscodeOptions | MergeAudioTranscodeOptions
| OnlyAudioTranscodeOptions | OnlyAudioTranscodeOptions
@ -204,13 +270,13 @@ function transcode (options: TranscodeOptions) {
.output(options.outputPath) .output(options.outputPath)
if (options.type === 'quick-transcode') { if (options.type === 'quick-transcode') {
command = await buildQuickTranscodeCommand(command) command = buildQuickTranscodeCommand(command)
} else if (options.type === 'hls') { } else if (options.type === 'hls') {
command = await buildHLSCommand(command, options) command = await buildHLSCommand(command, options)
} else if (options.type === 'merge-audio') { } else if (options.type === 'merge-audio') {
command = await buildAudioMergeCommand(command, options) command = await buildAudioMergeCommand(command, options)
} else if (options.type === 'only-audio') { } else if (options.type === 'only-audio') {
command = await buildOnlyAudioCommand(command, options) command = buildOnlyAudioCommand(command, options)
} else { } else {
command = await buildx264Command(command, options) command = await buildx264Command(command, options)
} }
@ -247,17 +313,17 @@ async function canDoQuickTranscode (path: string): Promise<boolean> {
// check video params // check video params
if (videoStream == null) return false if (videoStream == null) return false
if (videoStream[ 'codec_name' ] !== 'h264') return false if (videoStream['codec_name'] !== 'h264') return false
if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false if (videoStream['pix_fmt'] !== 'yuv420p') return false
if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) 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 if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
// check audio params (if audio stream exists) // check audio params (if audio stream exists)
if (parsedAudio.audioStream) { 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' ]) const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate'])
if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false
} }
return true return true
@ -333,14 +399,14 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M
return command return command
} }
async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) { function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
command = await presetOnlyAudio(command) command = presetOnlyAudio(command)
return command return command
} }
async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) { function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
command = await presetCopy(command) command = presetCopy(command)
command = command.outputOption('-map_metadata -1') // strip all metadata command = command.outputOption('-map_metadata -1') // strip all metadata
.outputOption('-movflags faststart') .outputOption('-movflags faststart')
@ -351,7 +417,7 @@ async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) { async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
const videoPath = getHLSVideoPath(options) const videoPath = getHLSVideoPath(options)
if (options.copyCodecs) command = await presetCopy(command) if (options.copyCodecs) command = presetCopy(command)
else command = await buildx264Command(command, options) else command = await buildx264Command(command, options)
command = command.outputOption('-hls_time 4') command = command.outputOption('-hls_time 4')
@ -418,71 +484,6 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string,
return localCommand 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. * Standard profile, with variable bitrate audio and faststart.
* *
@ -513,10 +514,10 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut
// of course this is far from perfect, but it might save some space in the end // of course this is far from perfect, but it might save some space in the end
localCommand = localCommand.audioCodec('aac') localCommand = localCommand.audioCodec('aac')
const audioCodecName = parsedAudio.audioStream[ 'codec_name' ] const audioCodecName = parsedAudio.audioStream['codec_name']
if (audio.bitrate[ audioCodecName ]) { if (audio.bitrate[audioCodecName]) {
const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ]) const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate'])
if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate) if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
} }
} }
@ -537,14 +538,14 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut
return localCommand return localCommand
} }
async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
return command return command
.format('mp4') .format('mp4')
.videoCodec('copy') .videoCodec('copy')
.audioCodec('copy') .audioCodec('copy')
} }
async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> { function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
return command return command
.format('mp4') .format('mp4')
.audioCodec('copy') .audioCodec('copy')

View File

@ -27,7 +27,7 @@ function getLoggerReplacer () {
if (value instanceof Error) { if (value instanceof Error) {
const error = {} const error = {}
Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ]) Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
return error return error
} }
@ -98,19 +98,20 @@ function bunyanLogFactory (level: string) {
let args: any[] = [] let args: any[] = []
args.concat(arguments) args.concat(arguments)
if (arguments[ 0 ] instanceof Error) { if (arguments[0] instanceof Error) {
meta = arguments[ 0 ].toString() meta = arguments[0].toString()
args = Array.prototype.slice.call(arguments, 1) args = Array.prototype.slice.call(arguments, 1)
args.push(meta) args.push(meta)
} else if (typeof (args[ 0 ]) !== 'string') { } else if (typeof (args[0]) !== 'string') {
meta = arguments[ 0 ] meta = arguments[0]
args = Array.prototype.slice.call(arguments, 1) args = Array.prototype.slice.call(arguments, 1)
args.push(meta) args.push(meta)
} }
logger[ level ].apply(logger, args) logger[level].apply(logger, args)
} }
} }
const bunyanLogger = { const bunyanLogger = {
trace: bunyanLogFactory('debug'), trace: bunyanLogFactory('debug'),
debug: bunyanLogFactory('debug'), debug: bunyanLogFactory('debug'),

View File

@ -1,8 +1,8 @@
// Thanks to https://regex101.com // Thanks to https://regex101.com
function regexpCapture (str: string, regex: RegExp, maxIterations = 100) { function regexpCapture (str: string, regex: RegExp, maxIterations = 100) {
const result: RegExpExecArray[] = []
let m: RegExpExecArray let m: RegExpExecArray
let i = 0 let i = 0
let result: RegExpExecArray[] = []
// tslint:disable:no-conditional-assignment // tslint:disable:no-conditional-assignment
while ((m = regex.exec(str)) !== null && i < maxIterations) { while ((m = regex.exec(str)) !== null && i < maxIterations) {

View File

@ -1,5 +1,5 @@
import { resolve } from 'path' import { resolve } from 'path'
const tsConfigPaths = require('tsconfig-paths') import tsConfigPaths = require('tsconfig-paths')
const tsConfig = require('../../tsconfig.json') const tsConfig = require('../../tsconfig.json')

View File

@ -21,7 +21,7 @@ async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: st
function isSignupAllowedForCurrentIP (ip: string) { function isSignupAllowedForCurrentIP (ip: string) {
const addr = ipaddr.parse(ip) const addr = ipaddr.parse(ip)
let excludeList = [ 'blacklist' ] const excludeList = [ 'blacklist' ]
let matched = '' let matched = ''
// if there is a valid, non-empty whitelist, we exclude all unknown adresses too // if there is a valid, non-empty whitelist, we exclude all unknown adresses too

View File

@ -1,6 +1,6 @@
import { ResultList } from '../../shared' import { ResultList } from '../../shared'
import { ApplicationModel } from '../models/application/application' 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 { logger } from './logger'
import { join } from 'path' import { join } from 'path'
import { Instance as ParseTorrent } from 'parse-torrent' import { Instance as ParseTorrent } from 'parse-torrent'
@ -14,7 +14,7 @@ function deleteFileAsync (path: string) {
} }
async function generateRandomString (size: number) { async function generateRandomString (size: number) {
const raw = await pseudoRandomBytesPromise(size) const raw = await randomBytesPromise(size)
return raw.toString('hex') return raw.toString('hex')
} }

View File

@ -39,7 +39,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
if (torrent.files.length !== 1) { if (torrent.files.length !== 1) {
if (timer) clearTimeout(timer) if (timer) clearTimeout(timer)
for (let file of torrent.files) { for (const file of torrent.files) {
deleteDownloadedFile({ directoryPath, filepath: file.path }) deleteDownloadedFile({ directoryPath, filepath: file.path })
} }
@ -47,15 +47,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
.then(() => rej(new Error('Cannot import torrent ' + torrentId + ': there are multiple files in it'))) .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 // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed
const writeStream = createWriteStream(path) const writeStream = createWriteStream(path)
writeStream.on('finish', () => { writeStream.on('finish', () => {
if (timer) clearTimeout(timer) 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)) .then(() => res(path))
.catch(err => logger.error('Cannot destroy webtorrent.', { err }))
}) })
file.createReadStream().pipe(writeStream) file.createReadStream().pipe(writeStream)
@ -63,9 +64,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
torrent.on('error', err => rej(err)) torrent.on('error', err => rej(err))
timer = setTimeout(async () => { timer = setTimeout(() => {
return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName) const err = new Error('Webtorrent download timeout.')
.then(() => rej(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) }, timeout)
}) })
} }

View File

@ -24,11 +24,12 @@ const processOptions = {
} }
function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> { 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' ] let args = opts || [ '-j', '--flat-playlist' ]
args = wrapWithProxyOptions(args) args = wrapWithProxyOptions(args)
const youtubeDL = await safeGetYoutubeDL() safeGetYoutubeDL()
.then(youtubeDL => {
youtubeDL.getInfo(url, args, processOptions, (err, info) => { youtubeDL.getInfo(url, args, processOptions, (err, info) => {
if (err) return rej(err) if (err) return rej(err)
if (info.is_live === true) return rej(new Error('Cannot download a live streaming.')) if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
@ -39,6 +40,8 @@ function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo>
return res(obj) return res(obj)
}) })
}) })
.catch(err => rej(err))
})
} }
function downloadYoutubeDLVideo (url: string, timeout: number) { function downloadYoutubeDLVideo (url: string, timeout: number) {
@ -54,8 +57,9 @@ function downloadYoutubeDLVideo (url: string, timeout: number) {
options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ]) options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ])
} }
return new Promise<string>(async (res, rej) => { return new Promise<string>((res, rej) => {
const youtubeDL = await safeGetYoutubeDL() safeGetYoutubeDL()
.then(youtubeDL => {
youtubeDL.exec(url, options, processOptions, err => { youtubeDL.exec(url, options, processOptions, err => {
clearTimeout(timer) clearTimeout(timer)
@ -69,12 +73,19 @@ function downloadYoutubeDLVideo (url: string, timeout: number) {
return res(path) return res(path)
}) })
timer = setTimeout(async () => { timer = setTimeout(() => {
await remove(path) const err = new Error('YoutubeDL download timeout.')
return rej(new Error('YoutubeDL download timeout.')) remove(path)
.finally(() => rej(err))
.catch(err => {
logger.error('Cannot remove %s in youtubeDL timeout.', path, { err })
return rej(err)
})
}, timeout) }, timeout)
}) })
.catch(err => rej(err))
})
} }
// Thanks: https://github.com/przemyslawpluta/node-youtube-dl/blob/master/lib/downloader.js // Thanks: https://github.com/przemyslawpluta/node-youtube-dl/blob/master/lib/downloader.js
@ -103,7 +114,7 @@ async function updateYoutubeDLBinary () {
const url = result.headers.location const url = result.headers.location
const downloadFile = request.get(url) 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 => { downloadFile.on('response', result => {
if (result.statusCode !== 200) { if (result.statusCode !== 200) {

View File

@ -3,7 +3,7 @@ import { isProdInstance, isTestInstance } from '../helpers/core-utils'
import { UserModel } from '../models/account/user' import { UserModel } from '../models/account/user'
import { ApplicationModel } from '../models/application/application' import { ApplicationModel } from '../models/application/application'
import { OAuthClientModel } from '../models/oauth/oauth-client' import { OAuthClientModel } from '../models/oauth/oauth-client'
import { parse } from 'url' import { URL } from 'url'
import { CONFIG } from './config' import { CONFIG } from './config'
import { logger } from '../helpers/logger' import { logger } from '../helpers/logger'
import { getServerActor } from '../helpers/utils' import { getServerActor } from '../helpers/utils'
@ -16,7 +16,7 @@ import { WEBSERVER } from './constants'
async function checkActivityPubUrls () { async function checkActivityPubUrls () {
const actor = await getServerActor() const actor = await getServerActor()
const parsed = parse(actor.url) const parsed = new URL(actor.url)
if (WEBSERVER.HOST !== parsed.host) { if (WEBSERVER.HOST !== parsed.host) {
const NODE_ENV = config.util.getEnv('NODE_ENV') const NODE_ENV = config.util.getEnv('NODE_ENV')
const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR') const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')

View File

@ -35,8 +35,8 @@ function checkMissedConfig () {
] ]
const requiredAlternatives = [ const requiredAlternatives = [
[ // set [ // set
['redis.hostname', 'redis.port'], // alternative [ 'redis.hostname', 'redis.port' ], // alternative
['redis.socket'] [ 'redis.socket' ]
] ]
] ]
const miss: string[] = [] const miss: string[] = []

View File

@ -301,7 +301,7 @@ function getLocalConfigFilePath () {
if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}` if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}` 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 buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
@ -330,7 +330,7 @@ export function reloadConfig () {
function purge () { function purge () {
for (const fileName in require.cache) { for (const fileName in require.cache) {
if (-1 === fileName.indexOf(directory())) { if (fileName.indexOf(directory()) === -1) {
continue continue
} }

View File

@ -4,7 +4,7 @@ import { ActivityPubActorType } from '../../shared/models/activitypub'
import { FollowState } from '../../shared/models/actors' import { FollowState } from '../../shared/models/actors'
import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos' import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
// Do not use barrels, remain constants as independent as possible // 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 { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
import { invert } from 'lodash' import { invert } from 'lodash'
import { CronRepeatOptions, EveryRepeatOptions } from 'bull' import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
@ -310,8 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour
const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = { const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
MIN: 10, MIN: 10,
STANDARD: [24, 25, 30], STANDARD: [ 24, 25, 30 ],
HD_STANDARD: [50, 60], HD_STANDARD: [ 50, 60 ],
AVERAGE: 30, AVERAGE: 30,
MAX: 60, MAX: 60,
KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum) KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
@ -361,42 +361,42 @@ const VIDEO_LICENCES = {
7: 'Public Domain Dedication' 7: 'Public Domain Dedication'
} }
let VIDEO_LANGUAGES: { [id: string]: string } = {} const VIDEO_LANGUAGES: { [id: string]: string } = {}
const VIDEO_PRIVACIES = { const VIDEO_PRIVACIES = {
[ VideoPrivacy.PUBLIC ]: 'Public', [VideoPrivacy.PUBLIC]: 'Public',
[ VideoPrivacy.UNLISTED ]: 'Unlisted', [VideoPrivacy.UNLISTED]: 'Unlisted',
[ VideoPrivacy.PRIVATE ]: 'Private', [VideoPrivacy.PRIVATE]: 'Private',
[ VideoPrivacy.INTERNAL ]: 'Internal' [VideoPrivacy.INTERNAL]: 'Internal'
} }
const VIDEO_STATES = { const VIDEO_STATES = {
[ VideoState.PUBLISHED ]: 'Published', [VideoState.PUBLISHED]: 'Published',
[ VideoState.TO_TRANSCODE ]: 'To transcode', [VideoState.TO_TRANSCODE]: 'To transcode',
[ VideoState.TO_IMPORT ]: 'To import' [VideoState.TO_IMPORT]: 'To import'
} }
const VIDEO_IMPORT_STATES = { const VIDEO_IMPORT_STATES = {
[ VideoImportState.FAILED ]: 'Failed', [VideoImportState.FAILED]: 'Failed',
[ VideoImportState.PENDING ]: 'Pending', [VideoImportState.PENDING]: 'Pending',
[ VideoImportState.SUCCESS ]: 'Success' [VideoImportState.SUCCESS]: 'Success'
} }
const VIDEO_ABUSE_STATES = { const VIDEO_ABUSE_STATES = {
[ VideoAbuseState.PENDING ]: 'Pending', [VideoAbuseState.PENDING]: 'Pending',
[ VideoAbuseState.REJECTED ]: 'Rejected', [VideoAbuseState.REJECTED]: 'Rejected',
[ VideoAbuseState.ACCEPTED ]: 'Accepted' [VideoAbuseState.ACCEPTED]: 'Accepted'
} }
const VIDEO_PLAYLIST_PRIVACIES = { const VIDEO_PLAYLIST_PRIVACIES = {
[ VideoPlaylistPrivacy.PUBLIC ]: 'Public', [VideoPlaylistPrivacy.PUBLIC]: 'Public',
[ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted', [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
[ VideoPlaylistPrivacy.PRIVATE ]: 'Private' [VideoPlaylistPrivacy.PRIVATE]: 'Private'
} }
const VIDEO_PLAYLIST_TYPES = { const VIDEO_PLAYLIST_TYPES = {
[ VideoPlaylistType.REGULAR ]: 'Regular', [VideoPlaylistType.REGULAR]: 'Regular',
[ VideoPlaylistType.WATCH_LATER ]: 'Watch later' [VideoPlaylistType.WATCH_LATER]: 'Watch later'
} }
const MIMETYPES = { const MIMETYPES = {
@ -533,7 +533,7 @@ const LAZY_STATIC_PATHS = {
} }
// Cache control // Cache control
let STATIC_MAX_AGE = { const STATIC_MAX_AGE = {
SERVER: '2h', SERVER: '2h',
CLIENT: '30d' CLIENT: '30d'
} }
@ -671,14 +671,14 @@ if (isTestInstance() === true) {
SCHEDULER_INTERVALS_MS.removeOldViews = 5000 SCHEDULER_INTERVALS_MS.removeOldViews = 5000
SCHEDULER_INTERVALS_MS.updateVideos = 5000 SCHEDULER_INTERVALS_MS.updateVideos = 5000
SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000 SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000
REPEAT_JOBS[ 'videos-views' ] = { every: 5000 } REPEAT_JOBS['videos-views'] = { every: 5000 }
REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1 REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1
VIDEO_VIEW_LIFETIME = 1000 // 1 second VIDEO_VIEW_LIFETIME = 1000 // 1 second
CONTACT_FORM_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 FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000
MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1
@ -838,42 +838,42 @@ function loadLanguages () {
function buildLanguages () { function buildLanguages () {
const iso639 = require('iso-639-3') const iso639 = require('iso-639-3')
const languages: { [ id: string ]: string } = {} const languages: { [id: string]: string } = {}
const additionalLanguages = { const additionalLanguages = {
'sgn': true, // Sign languages (macro language) sgn: true, // Sign languages (macro language)
'ase': true, // American sign language ase: true, // American sign language
'sdl': true, // Arabian sign language sdl: true, // Arabian sign language
'bfi': true, // British sign language bfi: true, // British sign language
'bzs': true, // Brazilian sign language bzs: true, // Brazilian sign language
'csl': true, // Chinese sign language csl: true, // Chinese sign language
'cse': true, // Czech sign language cse: true, // Czech sign language
'dsl': true, // Danish sign language dsl: true, // Danish sign language
'fsl': true, // French sign language fsl: true, // French sign language
'gsg': true, // German sign language gsg: true, // German sign language
'pks': true, // Pakistan sign language pks: true, // Pakistan sign language
'jsl': true, // Japanese sign language jsl: true, // Japanese sign language
'sfs': true, // South African sign language sfs: true, // South African sign language
'swl': true, // Swedish sign language swl: true, // Swedish sign language
'rsl': true, // Russian sign language: true rsl: true, // Russian sign language: true
'epo': true, // Esperanto epo: true, // Esperanto
'tlh': true, // Klingon tlh: true, // Klingon
'jbo': true, // Lojban jbo: true, // Lojban
'avk': true // Kotava avk: true // Kotava
} }
// Only add ISO639-1 languages and some sign languages (ISO639-3) // Only add ISO639-1 languages and some sign languages (ISO639-3)
iso639 iso639
.filter(l => { .filter(l => {
return (l.iso6391 !== null && l.type === 'living') || 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 // Override Occitan label
languages[ 'oc' ] = 'Occitan' languages['oc'] = 'Occitan'
languages[ 'el' ] = 'Greek' languages['el'] = 'Greek'
return languages return languages
} }

View File

@ -119,8 +119,6 @@ async function initDatabaseModels (silent: boolean) {
await createFunctions() await createFunctions()
if (!silent) logger.info('Database %s is ready.', dbname) if (!silent) logger.info('Database %s is ready.', dbname)
return
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -5,9 +5,9 @@ import { VideoModel } from '../../models/video/video'
import { getVideoFilePath } from '@server/lib/video-paths' import { getVideoFilePath } from '@server/lib/video-paths'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
return utils.db.Video.listOwnedAndPopulateAuthorAndTags() return utils.db.Video.listOwnedAndPopulateAuthorAndTags()

View File

@ -3,9 +3,9 @@ import * as Promise from 'bluebird'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -5,9 +5,9 @@ import { getVideoFileResolution } from '../../helpers/ffmpeg-utils'
import { readdir, rename } from 'fs-extra' import { readdir, rename } from 'fs-extra'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const torrentDir = CONFIG.STORAGE.TORRENTS_DIR const torrentDir = CONFIG.STORAGE.TORRENTS_DIR

View File

@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
import * as uuidv4 from 'uuid/v4' import * as uuidv4 from 'uuid/v4'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -7,9 +7,9 @@ import { ApplicationModel } from '../../models/application/application'
import { SERVER_ACTOR_NAME } from '../constants' import { SERVER_ACTOR_NAME } from '../constants'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.removeColumn('Servers', 'email') await utils.queryInterface.removeColumn('Servers', 'email')

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.removeColumn('Servers', 'publicKey') await utils.queryInterface.removeColumn('Servers', 'publicKey')

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
await utils.db.Avatar.sync() await utils.db.Avatar.sync()

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.renameTable('Applications', 'application') await utils.queryInterface.renameTable('Applications', 'application')

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import * as Promise from 'bluebird' import * as Promise from 'bluebird'
function up (utils: { function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const q = utils.queryInterface const q = utils.queryInterface

View File

@ -3,8 +3,8 @@ import { DataType } from 'sequelize-typescript'
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
// Create actor table // Create actor table

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import { WEBSERVER } from '../constants' import { WEBSERVER } from '../constants'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const toReplace = WEBSERVER.HOSTNAME + ':443' const toReplace = WEBSERVER.HOSTNAME + ':443'

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.dropTable('Authors') await utils.queryInterface.dropTable('Authors')

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey') await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey')

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import { Migration } from '../../models/migrations' import { Migration } from '../../models/migrations'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const data = { const data = {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import { ACTOR_FOLLOW_SCORE } from '../constants' import { ACTOR_FOLLOW_SCORE } from '../constants'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.removeColumn('server', 'score') await utils.queryInterface.removeColumn('server', 'score')

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
const query = 'UPDATE "actor" SET ' + const query = 'UPDATE "actor" SET ' +

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
await utils.queryInterface.dropTable('job') await utils.queryInterface.dropTable('job')

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {

View File

@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
import { CONSTRAINTS_FIELDS } from '../constants' import { CONSTRAINTS_FIELDS } from '../constants'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {

View File

@ -1,8 +1,8 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize sequelize: Sequelize.Sequelize
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,5 +1,4 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
import { VideoAbuseState } from '../../../shared/models/videos'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction transaction: Sequelize.Transaction

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
{ {

View File

@ -1,9 +1,9 @@
import * as Sequelize from 'sequelize' import * as Sequelize from 'sequelize'
async function up (utils: { async function up (utils: {
transaction: Sequelize.Transaction, transaction: Sequelize.Transaction
queryInterface: Sequelize.QueryInterface, queryInterface: Sequelize.QueryInterface
sequelize: Sequelize.Sequelize, sequelize: Sequelize.Sequelize
db: any db: any
}): Promise<void> { }): Promise<void> {
{ {

Some files were not shown because too many files have changed in this diff Show More