Move to eslint
This commit is contained in:
		
							parent
							
								
									a22046d166
								
							
						
					
					
						commit
						a15871560f
					
				
					 390 changed files with 3950 additions and 3615 deletions
				
			
		
							
								
								
									
										88
									
								
								.eslintrc.json
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								.eslintrc.json
									
										
									
									
									
										Normal 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"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								package.json
									
										
									
									
									
								
							
							
						
						
									
										15
									
								
								package.json
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -63,7 +63,7 @@
 | 
			
		|||
    "ng": "ng",
 | 
			
		||||
    "nodemon": "nodemon",
 | 
			
		||||
    "ts-node": "ts-node",
 | 
			
		||||
    "tslint": "tslint",
 | 
			
		||||
    "eslint": "eslint",
 | 
			
		||||
    "concurrently": "concurrently",
 | 
			
		||||
    "mocha-parallel-tests": "mocha-parallel-tests",
 | 
			
		||||
    "sasslint": "sass-lint --verbose --no-exit",
 | 
			
		||||
| 
						 | 
				
			
			@ -96,7 +96,7 @@
 | 
			
		|||
    "express": "^4.12.4",
 | 
			
		||||
    "express-oauth-server": "^2.0.0",
 | 
			
		||||
    "express-rate-limit": "^4.0.4",
 | 
			
		||||
    "express-validator": "^6.1.1",
 | 
			
		||||
    "express-validator": "^6.4.0",
 | 
			
		||||
    "flat": "^5.0.0",
 | 
			
		||||
    "fluent-ffmpeg": "^2.1.0",
 | 
			
		||||
    "fs-extra": "^8.0.1",
 | 
			
		||||
| 
						 | 
				
			
			@ -139,7 +139,7 @@
 | 
			
		|||
    "webtorrent": "^0.107.16",
 | 
			
		||||
    "winston": "3.2.1",
 | 
			
		||||
    "ws": "^7.0.0",
 | 
			
		||||
    "youtube-dl": "^3.0.1"
 | 
			
		||||
    "youtube-dl": "^3.0.2"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@types/apicache": "^1.2.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -180,10 +180,17 @@
 | 
			
		|||
    "@types/validator": "^12.0.1",
 | 
			
		||||
    "@types/webtorrent": "^0.107.0",
 | 
			
		||||
    "@types/ws": "^7.2.1",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^2.18.0",
 | 
			
		||||
    "chai": "^4.1.1",
 | 
			
		||||
    "chai-json-schema": "^1.5.0",
 | 
			
		||||
    "chai-xml": "^0.3.2",
 | 
			
		||||
    "concurrently": "^5.0.0",
 | 
			
		||||
    "eslint": "^6.8.0",
 | 
			
		||||
    "eslint-config-standard-with-typescript": "^12.0.1",
 | 
			
		||||
    "eslint-plugin-import": "^2.20.1",
 | 
			
		||||
    "eslint-plugin-node": "^11.0.0",
 | 
			
		||||
    "eslint-plugin-promise": "^4.2.1",
 | 
			
		||||
    "eslint-plugin-standard": "^4.0.1",
 | 
			
		||||
    "libxmljs": "0.19.7",
 | 
			
		||||
    "maildev": "^1.0.0-rc3",
 | 
			
		||||
    "marked": "^0.8.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -195,8 +202,6 @@
 | 
			
		|||
    "supertest": "^4.0.2",
 | 
			
		||||
    "swagger-cli": "^3.0.1",
 | 
			
		||||
    "ts-node": "8.6.2",
 | 
			
		||||
    "tslint": "^6.0.0",
 | 
			
		||||
    "tslint-config-standard": "^9.0.0",
 | 
			
		||||
    "typescript": "^3.7.2"
 | 
			
		||||
  },
 | 
			
		||||
  "scripty": {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ elif [ "$1" = "api-4" ]; then
 | 
			
		|||
    npm run build:server
 | 
			
		||||
    sh ./server/tests/api/ci-4.sh 2
 | 
			
		||||
elif [ "$1" = "lint" ]; then
 | 
			
		||||
    npm run tslint -- --project ./tsconfig.json -c ./tslint.json server.ts "server/**/*.ts" "shared/**/*.ts"
 | 
			
		||||
    npm run eslint -- --ext .ts "server/**/*.ts" "shared/**/*.ts"
 | 
			
		||||
    npm run swagger-cli -- validate support/doc/api/openapi.yaml
 | 
			
		||||
 | 
			
		||||
    ( cd client
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,6 @@ async function run () {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  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)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,7 +72,7 @@ async function run () {
 | 
			
		|||
  await JobQueue.Instance.init()
 | 
			
		||||
 | 
			
		||||
  for (const d of dataInput) {
 | 
			
		||||
    await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: d })
 | 
			
		||||
    await JobQueue.Instance.createJobWithPromise({ type: 'video-transcoding', payload: d })
 | 
			
		||||
    console.log('Transcoding job for video %s created.', video.uuid)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ activityPubClientRouter.get('/videos/watch/:videoId/comments/:commentId/activity
 | 
			
		|||
activityPubClientRouter.get('/video-channels/:name',
 | 
			
		||||
  executeIfActivityPub,
 | 
			
		||||
  asyncMiddleware(localVideoChannelValidator),
 | 
			
		||||
  asyncMiddleware(videoChannelController)
 | 
			
		||||
  videoChannelController
 | 
			
		||||
)
 | 
			
		||||
activityPubClientRouter.get('/video-channels/:name/followers',
 | 
			
		||||
  executeIfActivityPub,
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +154,7 @@ activityPubClientRouter.get('/video-playlists/:playlistId',
 | 
			
		|||
activityPubClientRouter.get('/video-playlists/:playlistId/:videoId',
 | 
			
		||||
  executeIfActivityPub,
 | 
			
		||||
  asyncMiddleware(videoPlaylistElementAPGetValidator),
 | 
			
		||||
  asyncMiddleware(videoPlaylistElementController)
 | 
			
		||||
  videoPlaylistElementController
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +281,7 @@ async function videoCommentsController (req: express.Request, res: express.Respo
 | 
			
		|||
  return activityPubResponse(activityPubContextify(json), res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function videoChannelController (req: express.Request, res: express.Response) {
 | 
			
		||||
function videoChannelController (req: express.Request, res: express.Response) {
 | 
			
		||||
  const videoChannel = res.locals.videoChannel
 | 
			
		||||
 | 
			
		||||
  return activityPubResponse(activityPubContextify(videoChannel.toActivityPubObject()), res)
 | 
			
		||||
| 
						 | 
				
			
			@ -353,7 +353,7 @@ async function videoPlaylistController (req: express.Request, res: express.Respo
 | 
			
		|||
  return activityPubResponse(activityPubContextify(object), res)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function videoPlaylistElementController (req: express.Request, res: express.Response) {
 | 
			
		||||
function videoPlaylistElementController (req: express.Request, res: express.Response) {
 | 
			
		||||
  const videoPlaylistElement = res.locals.videoPlaylistElementAP
 | 
			
		||||
 | 
			
		||||
  const json = videoPlaylistElement.toActivityPubObject()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,6 +46,10 @@ const inboxQueue = queue<QueueParam, Error>((task, cb) => {
 | 
			
		|||
 | 
			
		||||
  processActivities(task.activities, options)
 | 
			
		||||
    .then(() => cb())
 | 
			
		||||
    .catch(err => {
 | 
			
		||||
      logger.error('Error in process activities.', { err })
 | 
			
		||||
      cb()
 | 
			
		||||
    })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
function inboxController (req: express.Request, res: express.Response) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,21 +16,17 @@ import {
 | 
			
		|||
  accountNameWithHostGetValidator,
 | 
			
		||||
  accountsSortValidator,
 | 
			
		||||
  ensureAuthUserOwnsAccountValidator,
 | 
			
		||||
  videosSortValidator,
 | 
			
		||||
  videoChannelsSortValidator
 | 
			
		||||
  videoChannelsSortValidator,
 | 
			
		||||
  videosSortValidator
 | 
			
		||||
} from '../../middlewares/validators'
 | 
			
		||||
import { AccountModel } from '../../models/account/account'
 | 
			
		||||
import { AccountVideoRateModel } from '../../models/account/account-video-rate'
 | 
			
		||||
import { VideoModel } from '../../models/video/video'
 | 
			
		||||
import { buildNSFWFilter, isUserAbleToSearchRemoteURI, getCountVideos } from '../../helpers/express-utils'
 | 
			
		||||
import { buildNSFWFilter, getCountVideos, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
 | 
			
		||||
import { VideoChannelModel } from '../../models/video/video-channel'
 | 
			
		||||
import { JobQueue } from '../../lib/job-queue'
 | 
			
		||||
import { logger } from '../../helpers/logger'
 | 
			
		||||
import { VideoPlaylistModel } from '../../models/video/video-playlist'
 | 
			
		||||
import {
 | 
			
		||||
  commonVideoPlaylistFiltersValidator,
 | 
			
		||||
  videoPlaylistsSearchValidator
 | 
			
		||||
} from '../../middlewares/validators/videos/video-playlists'
 | 
			
		||||
import { commonVideoPlaylistFiltersValidator, videoPlaylistsSearchValidator } from '../../middlewares/validators/videos/video-playlists'
 | 
			
		||||
 | 
			
		||||
const accountsRouter = express.Router()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -104,7 +100,6 @@ function getAccount (req: express.Request, res: express.Response) {
 | 
			
		|||
 | 
			
		||||
  if (account.isOutdated()) {
 | 
			
		||||
    JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: account.Actor.url } })
 | 
			
		||||
            .catch(err => logger.error('Cannot create AP refresher job for actor %s.', account.Actor.url, { err }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.json(account.toFormattedJSON())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,12 +31,12 @@ configRouter.get('/',
 | 
			
		|||
configRouter.get('/custom',
 | 
			
		||||
  authenticate,
 | 
			
		||||
  ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
 | 
			
		||||
  asyncMiddleware(getCustomConfig)
 | 
			
		||||
  getCustomConfig
 | 
			
		||||
)
 | 
			
		||||
configRouter.put('/custom',
 | 
			
		||||
  authenticate,
 | 
			
		||||
  ensureUserHasRight(UserRight.MANAGE_CONFIGURATION),
 | 
			
		||||
  asyncMiddleware(customConfigUpdateValidator),
 | 
			
		||||
  customConfigUpdateValidator,
 | 
			
		||||
  asyncMiddleware(updateCustomConfig)
 | 
			
		||||
)
 | 
			
		||||
configRouter.delete('/custom',
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +196,7 @@ function getAbout (req: express.Request, res: express.Response) {
 | 
			
		|||
  return res.json(about).end()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getCustomConfig (req: express.Request, res: express.Response) {
 | 
			
		||||
function getCustomConfig (req: express.Request, res: express.Response) {
 | 
			
		||||
  const data = customConfig()
 | 
			
		||||
 | 
			
		||||
  return res.json(data).end()
 | 
			
		||||
| 
						 | 
				
			
			@ -250,7 +250,7 @@ function getRegisteredThemes () {
 | 
			
		|||
 | 
			
		||||
function getEnabledResolutions () {
 | 
			
		||||
  return Object.keys(CONFIG.TRANSCODING.RESOLUTIONS)
 | 
			
		||||
               .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[ key ] === true)
 | 
			
		||||
               .filter(key => CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.RESOLUTIONS[key] === true)
 | 
			
		||||
               .map(r => parseInt(r, 10))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -340,13 +340,13 @@ function customConfig (): CustomConfig {
 | 
			
		|||
      allowAudioFiles: CONFIG.TRANSCODING.ALLOW_AUDIO_FILES,
 | 
			
		||||
      threads: CONFIG.TRANSCODING.THREADS,
 | 
			
		||||
      resolutions: {
 | 
			
		||||
        '0p': CONFIG.TRANSCODING.RESOLUTIONS[ '0p' ],
 | 
			
		||||
        '240p': CONFIG.TRANSCODING.RESOLUTIONS[ '240p' ],
 | 
			
		||||
        '360p': CONFIG.TRANSCODING.RESOLUTIONS[ '360p' ],
 | 
			
		||||
        '480p': CONFIG.TRANSCODING.RESOLUTIONS[ '480p' ],
 | 
			
		||||
        '720p': CONFIG.TRANSCODING.RESOLUTIONS[ '720p' ],
 | 
			
		||||
        '1080p': CONFIG.TRANSCODING.RESOLUTIONS[ '1080p' ],
 | 
			
		||||
        '2160p': CONFIG.TRANSCODING.RESOLUTIONS[ '2160p' ]
 | 
			
		||||
        '0p': CONFIG.TRANSCODING.RESOLUTIONS['0p'],
 | 
			
		||||
        '240p': CONFIG.TRANSCODING.RESOLUTIONS['240p'],
 | 
			
		||||
        '360p': CONFIG.TRANSCODING.RESOLUTIONS['360p'],
 | 
			
		||||
        '480p': CONFIG.TRANSCODING.RESOLUTIONS['480p'],
 | 
			
		||||
        '720p': CONFIG.TRANSCODING.RESOLUTIONS['720p'],
 | 
			
		||||
        '1080p': CONFIG.TRANSCODING.RESOLUTIONS['1080p'],
 | 
			
		||||
        '2160p': CONFIG.TRANSCODING.RESOLUTIONS['2160p']
 | 
			
		||||
      },
 | 
			
		||||
      webtorrent: {
 | 
			
		||||
        enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,7 @@ async function listJobs (req: express.Request, res: express.Response) {
 | 
			
		|||
  })
 | 
			
		||||
  const total = await JobQueue.Instance.count(state)
 | 
			
		||||
 | 
			
		||||
  const result: ResultList<any> = {
 | 
			
		||||
  const result: ResultList<Job> = {
 | 
			
		||||
    total,
 | 
			
		||||
    data: jobs.map(j => formatJob(j, state))
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,7 +24,7 @@ export { overviewsRouter }
 | 
			
		|||
const buildSamples = memoizee(async function () {
 | 
			
		||||
  const [ categories, channels, tags ] = await Promise.all([
 | 
			
		||||
    VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
 | 
			
		||||
    VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT),
 | 
			
		||||
    VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT),
 | 
			
		||||
    TagModel.getRandomSamples(OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT)
 | 
			
		||||
  ])
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,13 +1,13 @@
 | 
			
		|||
import * as express from 'express'
 | 
			
		||||
import { UserRight } from '../../../../shared/models/users'
 | 
			
		||||
import { asyncMiddleware, authenticate, ensureUserHasRight } from '../../../middlewares'
 | 
			
		||||
import { authenticate, ensureUserHasRight } from '../../../middlewares'
 | 
			
		||||
 | 
			
		||||
const debugRouter = express.Router()
 | 
			
		||||
 | 
			
		||||
debugRouter.get('/debug',
 | 
			
		||||
  authenticate,
 | 
			
		||||
  ensureUserHasRight(UserRight.MANAGE_DEBUG),
 | 
			
		||||
  asyncMiddleware(getDebug)
 | 
			
		||||
  getDebug
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			@ -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({
 | 
			
		||||
    ip: req.ip
 | 
			
		||||
  }).end()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -135,7 +135,6 @@ async function followInstance (req: express.Request, res: express.Response) {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    JobQueue.Instance.createJob({ type: 'activitypub-follow', payload })
 | 
			
		||||
      .catch(err => logger.error('Cannot create follow job for %s.', host, err))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.status(204).end()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -59,9 +59,9 @@ async function getLogs (req: express.Request, res: express.Response) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
async function generateOutput (options: {
 | 
			
		||||
  startDateQuery: string,
 | 
			
		||||
  endDateQuery?: string,
 | 
			
		||||
  level: LogLevel,
 | 
			
		||||
  startDateQuery: string
 | 
			
		||||
  endDateQuery?: string
 | 
			
		||||
  level: LogLevel
 | 
			
		||||
  nameFilter: RegExp
 | 
			
		||||
}) {
 | 
			
		||||
  const { startDateQuery, level, nameFilter } = options
 | 
			
		||||
| 
						 | 
				
			
			@ -111,7 +111,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
 | 
			
		|||
  const output: any[] = []
 | 
			
		||||
 | 
			
		||||
  for (let i = lines.length - 1; i >= 0; i--) {
 | 
			
		||||
    const line = lines[ i ]
 | 
			
		||||
    const line = lines[i]
 | 
			
		||||
    let log: any
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +122,7 @@ async function getOutputFromFile (path: string, startDate: Date, endDate: Date,
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    logTime = new Date(log.timestamp).getTime()
 | 
			
		||||
    if (logTime >= startTime && logTime <= endTime && logsLevel[ log.level ] >= logsLevel[ level ]) {
 | 
			
		||||
    if (logTime >= startTime && logTime <= endTime && logsLevel[log.level] >= logsLevel[level]) {
 | 
			
		||||
      output.push(log)
 | 
			
		||||
 | 
			
		||||
      currentSize += line.length
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ async function addVideoRedundancy (req: express.Request, res: express.Response)
 | 
			
		|||
    videoId: res.locals.onlyVideo.id
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  await JobQueue.Instance.createJob({
 | 
			
		||||
  await JobQueue.Instance.createJobWithPromise({
 | 
			
		||||
    type: 'video-redundancy',
 | 
			
		||||
    payload
 | 
			
		||||
  })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ meRouter.get('/me',
 | 
			
		|||
)
 | 
			
		||||
meRouter.delete('/me',
 | 
			
		||||
  authenticate,
 | 
			
		||||
  asyncMiddleware(deleteMeValidator),
 | 
			
		||||
  deleteMeValidator,
 | 
			
		||||
  asyncMiddleware(deleteMe)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +214,7 @@ async function updateMe (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 userAccount = await AccountModel.load(user.Account.id)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,7 +19,6 @@ import { buildNSFWFilter, getCountVideos } from '../../../helpers/express-utils'
 | 
			
		|||
import { VideoFilter } from '../../../../shared/models/videos/video-query.type'
 | 
			
		||||
import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 | 
			
		||||
import { JobQueue } from '../../../lib/job-queue'
 | 
			
		||||
import { logger } from '../../../helpers/logger'
 | 
			
		||||
import { sequelizeTypescript } from '../../../initializers/database'
 | 
			
		||||
 | 
			
		||||
const mySubscriptionsRouter = express.Router()
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +51,7 @@ mySubscriptionsRouter.get('/me/subscriptions',
 | 
			
		|||
mySubscriptionsRouter.post('/me/subscriptions',
 | 
			
		||||
  authenticate,
 | 
			
		||||
  userSubscriptionAddValidator,
 | 
			
		||||
  asyncMiddleware(addUserSubscription)
 | 
			
		||||
  addUserSubscription
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
mySubscriptionsRouter.get('/me/subscriptions/:uri',
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +105,7 @@ async function areSubscriptionsExist (req: express.Request, res: express.Respons
 | 
			
		|||
  return res.json(existObject)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function addUserSubscription (req: express.Request, res: express.Response) {
 | 
			
		||||
function addUserSubscription (req: express.Request, res: express.Response) {
 | 
			
		||||
  const user = res.locals.oauth.token.User
 | 
			
		||||
  const [ name, host ] = req.body.uri.split('@')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -117,7 +116,6 @@ async function addUserSubscription (req: express.Request, res: express.Response)
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  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()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,7 +119,7 @@ async function listVideoChannels (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 oldVideoChannelAuditKeys = new VideoChannelAuditView(videoChannel.toFormattedJSON())
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -232,7 +232,6 @@ async function getVideoChannel (req: express.Request, res: express.Response) {
 | 
			
		|||
 | 
			
		||||
  if (videoChannelWithVideos.isOutdated()) {
 | 
			
		||||
    JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'actor', url: videoChannelWithVideos.Actor.url } })
 | 
			
		||||
            .catch(err => logger.error('Cannot create AP refresher job for actor %s.', videoChannelWithVideos.Actor.url, { err }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.json(videoChannelWithVideos.toFormattedJSON())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,7 +144,6 @@ function getVideoPlaylist (req: express.Request, res: express.Response) {
 | 
			
		|||
 | 
			
		||||
  if (videoPlaylist.isOutdated()) {
 | 
			
		||||
    JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: videoPlaylist.url } })
 | 
			
		||||
            .catch(err => logger.error('Cannot create AP refresher job for playlist %s.', videoPlaylist.url, { err }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.json(videoPlaylist.toFormattedJSON())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,12 +88,12 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
 | 
			
		|||
    const buf = await readFile(torrentfile.path)
 | 
			
		||||
    const parsedTorrent = parseTorrent(buf)
 | 
			
		||||
 | 
			
		||||
    videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[ 0 ] : parsedTorrent.name as string
 | 
			
		||||
    videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string
 | 
			
		||||
  } else {
 | 
			
		||||
    magnetUri = body.magnetUri
 | 
			
		||||
 | 
			
		||||
    const parsed = magnetUtil.decode(magnetUri)
 | 
			
		||||
    videoName = isArray(parsed.name) ? parsed.name[ 0 ] : parsed.name as string
 | 
			
		||||
    videoName = isArray(parsed.name) ? parsed.name[0] : parsed.name as string
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const video = buildVideo(res.locals.videoChannel.id, body, { name: videoName })
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +124,7 @@ async function addTorrentImport (req: express.Request, res: express.Response, to
 | 
			
		|||
    videoImportId: videoImport.id,
 | 
			
		||||
    magnetUri
 | 
			
		||||
  }
 | 
			
		||||
  await JobQueue.Instance.createJob({ type: 'video-import', payload })
 | 
			
		||||
  await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
 | 
			
		||||
 | 
			
		||||
  auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -176,7 +176,7 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response)
 | 
			
		|||
    downloadThumbnail: !thumbnailModel,
 | 
			
		||||
    downloadPreview: !previewModel
 | 
			
		||||
  }
 | 
			
		||||
  await JobQueue.Instance.createJob({ type: 'video-import', payload })
 | 
			
		||||
  await JobQueue.Instance.createJobWithPromise({ type: 'video-import', payload })
 | 
			
		||||
 | 
			
		||||
  auditLogger.create(getAuditIdFromRes(res), new VideoImportAuditView(videoImport.toFormattedJSON()))
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -211,7 +211,7 @@ function buildVideo (channelId: number, body: VideoImportCreate, importData: You
 | 
			
		|||
async function processThumbnail (req: express.Request, video: VideoModel) {
 | 
			
		||||
  const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined
 | 
			
		||||
  if (thumbnailField) {
 | 
			
		||||
    const thumbnailPhysicalFile = thumbnailField[ 0 ]
 | 
			
		||||
    const thumbnailPhysicalFile = thumbnailField[0]
 | 
			
		||||
 | 
			
		||||
    return createVideoMiniatureFromExisting(thumbnailPhysicalFile.path, video, ThumbnailType.MINIATURE, false)
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -231,12 +231,12 @@ async function processPreview (req: express.Request, video: VideoModel) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function insertIntoDB (parameters: {
 | 
			
		||||
  video: MVideoThumbnailAccountDefault,
 | 
			
		||||
  thumbnailModel: MThumbnail,
 | 
			
		||||
  previewModel: MThumbnail,
 | 
			
		||||
  videoChannel: MChannelAccountDefault,
 | 
			
		||||
  tags: string[],
 | 
			
		||||
  videoImportAttributes: Partial<MVideoImport>,
 | 
			
		||||
  video: MVideoThumbnailAccountDefault
 | 
			
		||||
  thumbnailModel: MThumbnail
 | 
			
		||||
  previewModel: MThumbnail
 | 
			
		||||
  videoChannel: MChannelAccountDefault
 | 
			
		||||
  tags: string[]
 | 
			
		||||
  videoImportAttributes: Partial<MVideoImport>
 | 
			
		||||
  user: MUser
 | 
			
		||||
}): Bluebird<MVideoImportFormattable> {
 | 
			
		||||
  const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,8 +12,7 @@ import {
 | 
			
		|||
  VIDEO_CATEGORIES,
 | 
			
		||||
  VIDEO_LANGUAGES,
 | 
			
		||||
  VIDEO_LICENCES,
 | 
			
		||||
  VIDEO_PRIVACIES,
 | 
			
		||||
  VIDEO_TRANSCODING_FPS
 | 
			
		||||
  VIDEO_PRIVACIES
 | 
			
		||||
} from '../../../initializers/constants'
 | 
			
		||||
import {
 | 
			
		||||
  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 })
 | 
			
		||||
| 
						 | 
				
			
			@ -453,7 +452,6 @@ async function getVideo (req: express.Request, res: express.Response) {
 | 
			
		|||
 | 
			
		||||
  if (video.isOutdated()) {
 | 
			
		||||
    JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } })
 | 
			
		||||
      .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return res.json(video.toFormattedDetailsJSON())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 file = req.params.file
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,12 +45,12 @@ staticRouter.use(
 | 
			
		|||
staticRouter.use(
 | 
			
		||||
  STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+).torrent',
 | 
			
		||||
  asyncMiddleware(videosDownloadValidator),
 | 
			
		||||
  asyncMiddleware(downloadTorrent)
 | 
			
		||||
  downloadTorrent
 | 
			
		||||
)
 | 
			
		||||
staticRouter.use(
 | 
			
		||||
  STATIC_DOWNLOAD_PATHS.TORRENTS + ':id-:resolution([0-9]+)-hls.torrent',
 | 
			
		||||
  asyncMiddleware(videosDownloadValidator),
 | 
			
		||||
  asyncMiddleware(downloadHLSVideoFileTorrent)
 | 
			
		||||
  downloadHLSVideoFileTorrent
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Videos path for webseeding
 | 
			
		||||
| 
						 | 
				
			
			@ -68,13 +68,13 @@ staticRouter.use(
 | 
			
		|||
staticRouter.use(
 | 
			
		||||
  STATIC_DOWNLOAD_PATHS.VIDEOS + ':id-:resolution([0-9]+).:extension',
 | 
			
		||||
  asyncMiddleware(videosDownloadValidator),
 | 
			
		||||
  asyncMiddleware(downloadVideoFile)
 | 
			
		||||
  downloadVideoFile
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
staticRouter.use(
 | 
			
		||||
  STATIC_DOWNLOAD_PATHS.HLS_VIDEOS + ':id-:resolution([0-9]+)-fragmented.:extension',
 | 
			
		||||
  asyncMiddleware(videosDownloadValidator),
 | 
			
		||||
  asyncMiddleware(downloadHLSVideoFile)
 | 
			
		||||
  downloadHLSVideoFile
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// HLS
 | 
			
		||||
| 
						 | 
				
			
			@ -325,7 +325,7 @@ async function generateNodeinfo (req: express.Request, res: express.Response) {
 | 
			
		|||
  return res.send(json).end()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function downloadTorrent (req: express.Request, res: express.Response) {
 | 
			
		||||
function downloadTorrent (req: express.Request, res: express.Response) {
 | 
			
		||||
  const video = res.locals.videoAll
 | 
			
		||||
 | 
			
		||||
  const videoFile = getVideoFile(req, video.VideoFiles)
 | 
			
		||||
| 
						 | 
				
			
			@ -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`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
 | 
			
		||||
function downloadHLSVideoFileTorrent (req: express.Request, res: express.Response) {
 | 
			
		||||
  const video = res.locals.videoAll
 | 
			
		||||
 | 
			
		||||
  const playlist = getHLSPlaylist(video)
 | 
			
		||||
| 
						 | 
				
			
			@ -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`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function downloadVideoFile (req: express.Request, res: express.Response) {
 | 
			
		||||
function downloadVideoFile (req: express.Request, res: express.Response) {
 | 
			
		||||
  const video = res.locals.videoAll
 | 
			
		||||
 | 
			
		||||
  const videoFile = getVideoFile(req, video.VideoFiles)
 | 
			
		||||
| 
						 | 
				
			
			@ -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}`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function downloadHLSVideoFile (req: express.Request, res: express.Response) {
 | 
			
		||||
function downloadHLSVideoFile (req: express.Request, res: express.Response) {
 | 
			
		||||
  const video = res.locals.videoAll
 | 
			
		||||
  const playlist = getHLSPlaylist(video)
 | 
			
		||||
  if (!playlist) return res.status(404).end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,6 @@ import * as proxyAddr from 'proxy-addr'
 | 
			
		|||
import { Server as WebSocketServer } from 'ws'
 | 
			
		||||
import { TRACKER_RATE_LIMITS } from '../initializers/constants'
 | 
			
		||||
import { VideoFileModel } from '../models/video/video-file'
 | 
			
		||||
import { parse } from 'url'
 | 
			
		||||
import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
 | 
			
		||||
import { CONFIG } from '../initializers/config'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -38,11 +37,11 @@ const trackerServer = new TrackerServer({
 | 
			
		|||
 | 
			
		||||
    const key = ip + '-' + infoHash
 | 
			
		||||
 | 
			
		||||
    peersIps[ ip ] = peersIps[ ip ] ? peersIps[ ip ] + 1 : 1
 | 
			
		||||
    peersIpInfoHash[ key ] = peersIpInfoHash[ key ] ? peersIpInfoHash[ key ] + 1 : 1
 | 
			
		||||
    peersIps[ip] = peersIps[ip] ? peersIps[ip] + 1 : 1
 | 
			
		||||
    peersIpInfoHash[key] = peersIpInfoHash[key] ? peersIpInfoHash[key] + 1 : 1
 | 
			
		||||
 | 
			
		||||
    if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[ key ] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
 | 
			
		||||
      return cb(new Error(`Too many requests (${peersIpInfoHash[ key ]} of ip ${ip} for torrent ${infoHash}`))
 | 
			
		||||
    if (CONFIG.TRACKER.REJECT_TOO_MANY_ANNOUNCES && peersIpInfoHash[key] > TRACKER_RATE_LIMITS.ANNOUNCES_PER_IP_PER_INFOHASH) {
 | 
			
		||||
      return cb(new Error(`Too many requests (${peersIpInfoHash[key]} of ip ${ip} for torrent ${infoHash}`))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
| 
						 | 
				
			
			@ -87,10 +86,8 @@ function createWebsocketTrackerServer (app: express.Application) {
 | 
			
		|||
    trackerServer.onWebSocketConnection(ws)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  server.on('upgrade', (request, socket, head) => {
 | 
			
		||||
    const pathname = parse(request.url).pathname
 | 
			
		||||
 | 
			
		||||
    if (pathname === '/tracker/socket') {
 | 
			
		||||
  server.on('upgrade', (request: express.Request, socket, head) => {
 | 
			
		||||
    if (request.path === '/tracker/socket') {
 | 
			
		||||
      wss.handleUpgrade(request, socket, head, ws => wss.emit('connection', ws, request))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,7 @@ import { Activity } from '../../shared/models/activitypub'
 | 
			
		|||
import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants'
 | 
			
		||||
import { signJsonLDObject } from './peertube-crypto'
 | 
			
		||||
import { pageToStartAndCount } from './core-utils'
 | 
			
		||||
import { parse } from 'url'
 | 
			
		||||
import { URL } from 'url'
 | 
			
		||||
import { MActor, MVideoAccountLight } from '../typings/models'
 | 
			
		||||
 | 
			
		||||
function activityPubContextify <T> (data: T) {
 | 
			
		||||
| 
						 | 
				
			
			@ -161,8 +161,8 @@ function getAPId (activity: string | { id: string }) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function checkUrlsSameHost (url1: string, url2: string) {
 | 
			
		||||
  const idHost = parse(url1).host
 | 
			
		||||
  const actorHost = parse(url2).host
 | 
			
		||||
  const idHost = new URL(url1).host
 | 
			
		||||
  const actorHost = new URL(url2).host
 | 
			
		||||
 | 
			
		||||
  return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -81,7 +81,8 @@ function auditLoggerFactory (domain: string) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
abstract class EntityAuditView {
 | 
			
		||||
  constructor (private keysToKeep: Array<string>, private prefix: string, private entityInfos: object) { }
 | 
			
		||||
  constructor (private readonly keysToKeep: string[], private readonly prefix: string, private readonly entityInfos: object) { }
 | 
			
		||||
 | 
			
		||||
  toLogKeys (): object {
 | 
			
		||||
    return chain(flatten(this.entityInfos, { delimiter: '-', safe: true }))
 | 
			
		||||
      .pick(this.keysToKeep)
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +122,7 @@ const videoKeysToKeep = [
 | 
			
		|||
  'downloadEnabled'
 | 
			
		||||
]
 | 
			
		||||
class VideoAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private video: VideoDetails) {
 | 
			
		||||
  constructor (private readonly video: VideoDetails) {
 | 
			
		||||
    super(videoKeysToKeep, 'video', video)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +133,7 @@ const videoImportKeysToKeep = [
 | 
			
		|||
  'video-name'
 | 
			
		||||
]
 | 
			
		||||
class VideoImportAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private videoImport: VideoImport) {
 | 
			
		||||
  constructor (private readonly videoImport: VideoImport) {
 | 
			
		||||
    super(videoImportKeysToKeep, 'video-import', videoImport)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +152,7 @@ const commentKeysToKeep = [
 | 
			
		|||
  'account-name'
 | 
			
		||||
]
 | 
			
		||||
class CommentAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private comment: VideoComment) {
 | 
			
		||||
  constructor (private readonly comment: VideoComment) {
 | 
			
		||||
    super(commentKeysToKeep, 'comment', comment)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -180,7 +181,7 @@ const userKeysToKeep = [
 | 
			
		|||
  'videoChannels'
 | 
			
		||||
]
 | 
			
		||||
class UserAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private user: User) {
 | 
			
		||||
  constructor (private readonly user: User) {
 | 
			
		||||
    super(userKeysToKeep, 'user', user)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -206,7 +207,7 @@ const channelKeysToKeep = [
 | 
			
		|||
  'ownerAccount-displayedName'
 | 
			
		||||
]
 | 
			
		||||
class VideoChannelAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private channel: VideoChannel) {
 | 
			
		||||
  constructor (private readonly channel: VideoChannel) {
 | 
			
		||||
    super(channelKeysToKeep, 'channel', channel)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +222,7 @@ const videoAbuseKeysToKeep = [
 | 
			
		|||
  'createdAt'
 | 
			
		||||
]
 | 
			
		||||
class VideoAbuseAuditView extends EntityAuditView {
 | 
			
		||||
  constructor (private videoAbuse: VideoAbuse) {
 | 
			
		||||
  constructor (private readonly videoAbuse: VideoAbuse) {
 | 
			
		||||
    super(videoAbuseKeysToKeep, 'abuse', videoAbuse)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -253,9 +254,12 @@ class CustomConfigAuditView extends EntityAuditView {
 | 
			
		|||
    const infos: any = customConfig
 | 
			
		||||
    const resolutionsDict = infos.transcoding.resolutions
 | 
			
		||||
    const resolutionsArray = []
 | 
			
		||||
    Object.entries(resolutionsDict).forEach(([resolution, isEnabled]) => {
 | 
			
		||||
      if (isEnabled) resolutionsArray.push(resolution)
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    Object.entries(resolutionsDict)
 | 
			
		||||
          .forEach(([ resolution, isEnabled ]) => {
 | 
			
		||||
            if (isEnabled) resolutionsArray.push(resolution)
 | 
			
		||||
          })
 | 
			
		||||
 | 
			
		||||
    Object.assign({}, infos, { transcoding: { resolutions: resolutionsArray } })
 | 
			
		||||
    super(customConfigKeysToKeep, 'config', infos)
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,11 @@
 | 
			
		|||
/* eslint-disable no-useless-call */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
  Different from 'utils' because we don't not import other PeerTube modules.
 | 
			
		||||
  Useful to avoid circular dependencies.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto'
 | 
			
		||||
import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto'
 | 
			
		||||
import { basename, isAbsolute, join, resolve } from 'path'
 | 
			
		||||
import * as pem from 'pem'
 | 
			
		||||
import { URL } from 'url'
 | 
			
		||||
| 
						 | 
				
			
			@ -22,31 +24,31 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va
 | 
			
		|||
  const newObject = {}
 | 
			
		||||
  Object.keys(oldObject).forEach(oldKey => {
 | 
			
		||||
    const newKey = keyConverter(oldKey)
 | 
			
		||||
    newObject[ newKey ] = objectConverter(oldObject[ oldKey ], keyConverter, valueConverter)
 | 
			
		||||
    newObject[newKey] = objectConverter(oldObject[oldKey], keyConverter, valueConverter)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  return newObject
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const timeTable = {
 | 
			
		||||
  ms:           1,
 | 
			
		||||
  second:       1000,
 | 
			
		||||
  minute:       60000,
 | 
			
		||||
  hour:         3600000,
 | 
			
		||||
  day:          3600000 * 24,
 | 
			
		||||
  week:         3600000 * 24 * 7,
 | 
			
		||||
  month:        3600000 * 24 * 30
 | 
			
		||||
  ms: 1,
 | 
			
		||||
  second: 1000,
 | 
			
		||||
  minute: 60000,
 | 
			
		||||
  hour: 3600000,
 | 
			
		||||
  day: 3600000 * 24,
 | 
			
		||||
  week: 3600000 * 24 * 7,
 | 
			
		||||
  month: 3600000 * 24 * 30
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function parseDurationToMs (duration: number | string): number {
 | 
			
		||||
  if (typeof duration === 'number') return duration
 | 
			
		||||
 | 
			
		||||
  if (typeof duration === 'string') {
 | 
			
		||||
    const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
 | 
			
		||||
    const split = duration.match(/^([\d.,]+)\s?(\w+)$/)
 | 
			
		||||
 | 
			
		||||
    if (split.length === 3) {
 | 
			
		||||
      const len = parseFloat(split[1])
 | 
			
		||||
      let unit = split[2].replace(/s$/i,'').toLowerCase()
 | 
			
		||||
      let unit = split[2].replace(/s$/i, '').toLowerCase()
 | 
			
		||||
      if (unit === 'm') {
 | 
			
		||||
        unit = 'ms'
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -73,21 +75,21 @@ export function parseBytes (value: string | number): number {
 | 
			
		|||
 | 
			
		||||
  if (value.match(tgm)) {
 | 
			
		||||
    match = value.match(tgm)
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
 | 
			
		||||
    + parseInt(match[2], 10) * 1024 * 1024 * 1024
 | 
			
		||||
    + parseInt(match[3], 10) * 1024 * 1024
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
 | 
			
		||||
      parseInt(match[2], 10) * 1024 * 1024 * 1024 +
 | 
			
		||||
      parseInt(match[3], 10) * 1024 * 1024
 | 
			
		||||
  } else if (value.match(tg)) {
 | 
			
		||||
    match = value.match(tg)
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
 | 
			
		||||
    + parseInt(match[2], 10) * 1024 * 1024 * 1024
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
 | 
			
		||||
      parseInt(match[2], 10) * 1024 * 1024 * 1024
 | 
			
		||||
  } else if (value.match(tm)) {
 | 
			
		||||
    match = value.match(tm)
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
 | 
			
		||||
    + parseInt(match[2], 10) * 1024 * 1024
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024 +
 | 
			
		||||
      parseInt(match[2], 10) * 1024 * 1024
 | 
			
		||||
  } else if (value.match(gm)) {
 | 
			
		||||
    match = value.match(gm)
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024
 | 
			
		||||
    + parseInt(match[2], 10) * 1024 * 1024
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 +
 | 
			
		||||
      parseInt(match[2], 10) * 1024 * 1024
 | 
			
		||||
  } else if (value.match(t)) {
 | 
			
		||||
    match = value.match(t)
 | 
			
		||||
    return parseInt(match[1], 10) * 1024 * 1024 * 1024 * 1024
 | 
			
		||||
| 
						 | 
				
			
			@ -137,6 +139,7 @@ function getAppNumber () {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
let rootPath: string
 | 
			
		||||
 | 
			
		||||
function root () {
 | 
			
		||||
  if (rootPath) return rootPath
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +166,7 @@ function escapeHTML (stringParam) {
 | 
			
		|||
    '=': '='
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s])
 | 
			
		||||
  return String(stringParam).replace(/[&<>"'`=/]/g, s => entityMap[s])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function pageToStartAndCount (page: number, itemsPerPage: number) {
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +205,7 @@ function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex')
 | 
			
		|||
function execShell (command: string, options?: ExecOptions) {
 | 
			
		||||
  return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => {
 | 
			
		||||
    exec(command, options, (err, stdout, stderr) => {
 | 
			
		||||
      // eslint-disable-next-line prefer-promise-reject-errors
 | 
			
		||||
      if (err) return rej({ err, stdout, stderr })
 | 
			
		||||
 | 
			
		||||
      return res({ stdout, stderr })
 | 
			
		||||
| 
						 | 
				
			
			@ -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> {
 | 
			
		||||
  return function promisified (arg1: T, arg2: U): Promise<A> {
 | 
			
		||||
    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> {
 | 
			
		||||
  return function promisified (arg1: T, arg2: U): Promise<void> {
 | 
			
		||||
    return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
 | 
			
		||||
      func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ])
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
 | 
			
		||||
const randomBytesPromise = promisify1<number, Buffer>(randomBytes)
 | 
			
		||||
const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
 | 
			
		||||
const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
 | 
			
		||||
const execPromise2 = promisify2<string, any, string>(exec)
 | 
			
		||||
| 
						 | 
				
			
			@ -280,7 +268,7 @@ export {
 | 
			
		|||
  promisify1,
 | 
			
		||||
  promisify2,
 | 
			
		||||
 | 
			
		||||
  pseudoRandomBytesPromise,
 | 
			
		||||
  randomBytesPromise,
 | 
			
		||||
  createPrivateKey,
 | 
			
		||||
  getPublicKey,
 | 
			
		||||
  execPromise2,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,52 +5,52 @@ import { logger } from './logger'
 | 
			
		|||
const CACHE = {
 | 
			
		||||
  'https://w3id.org/security/v1': {
 | 
			
		||||
    '@context': {
 | 
			
		||||
      'id': '@id',
 | 
			
		||||
      'type': '@type',
 | 
			
		||||
      id: '@id',
 | 
			
		||||
      type: '@type',
 | 
			
		||||
 | 
			
		||||
      'dc': 'http://purl.org/dc/terms/',
 | 
			
		||||
      'sec': 'https://w3id.org/security#',
 | 
			
		||||
      'xsd': 'http://www.w3.org/2001/XMLSchema#',
 | 
			
		||||
      dc: 'http://purl.org/dc/terms/',
 | 
			
		||||
      sec: 'https://w3id.org/security#',
 | 
			
		||||
      xsd: 'http://www.w3.org/2001/XMLSchema#',
 | 
			
		||||
 | 
			
		||||
      'EcdsaKoblitzSignature2016': 'sec:EcdsaKoblitzSignature2016',
 | 
			
		||||
      'Ed25519Signature2018': 'sec:Ed25519Signature2018',
 | 
			
		||||
      'EncryptedMessage': 'sec:EncryptedMessage',
 | 
			
		||||
      'GraphSignature2012': 'sec:GraphSignature2012',
 | 
			
		||||
      'LinkedDataSignature2015': 'sec:LinkedDataSignature2015',
 | 
			
		||||
      'LinkedDataSignature2016': 'sec:LinkedDataSignature2016',
 | 
			
		||||
      'CryptographicKey': 'sec:Key',
 | 
			
		||||
      EcdsaKoblitzSignature2016: 'sec:EcdsaKoblitzSignature2016',
 | 
			
		||||
      Ed25519Signature2018: 'sec:Ed25519Signature2018',
 | 
			
		||||
      EncryptedMessage: 'sec:EncryptedMessage',
 | 
			
		||||
      GraphSignature2012: 'sec:GraphSignature2012',
 | 
			
		||||
      LinkedDataSignature2015: 'sec:LinkedDataSignature2015',
 | 
			
		||||
      LinkedDataSignature2016: 'sec:LinkedDataSignature2016',
 | 
			
		||||
      CryptographicKey: 'sec:Key',
 | 
			
		||||
 | 
			
		||||
      'authenticationTag': 'sec:authenticationTag',
 | 
			
		||||
      'canonicalizationAlgorithm': 'sec:canonicalizationAlgorithm',
 | 
			
		||||
      'cipherAlgorithm': 'sec:cipherAlgorithm',
 | 
			
		||||
      'cipherData': 'sec:cipherData',
 | 
			
		||||
      'cipherKey': 'sec:cipherKey',
 | 
			
		||||
      'created': { '@id': 'dc:created', '@type': 'xsd:dateTime' },
 | 
			
		||||
      'creator': { '@id': 'dc:creator', '@type': '@id' },
 | 
			
		||||
      'digestAlgorithm': 'sec:digestAlgorithm',
 | 
			
		||||
      'digestValue': 'sec:digestValue',
 | 
			
		||||
      'domain': 'sec:domain',
 | 
			
		||||
      'encryptionKey': 'sec:encryptionKey',
 | 
			
		||||
      'expiration': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
 | 
			
		||||
      'expires': { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
 | 
			
		||||
      'initializationVector': 'sec:initializationVector',
 | 
			
		||||
      'iterationCount': 'sec:iterationCount',
 | 
			
		||||
      'nonce': 'sec:nonce',
 | 
			
		||||
      'normalizationAlgorithm': 'sec:normalizationAlgorithm',
 | 
			
		||||
      'owner': { '@id': 'sec:owner', '@type': '@id' },
 | 
			
		||||
      'password': 'sec:password',
 | 
			
		||||
      'privateKey': { '@id': 'sec:privateKey', '@type': '@id' },
 | 
			
		||||
      'privateKeyPem': 'sec:privateKeyPem',
 | 
			
		||||
      'publicKey': { '@id': 'sec:publicKey', '@type': '@id' },
 | 
			
		||||
      'publicKeyBase58': 'sec:publicKeyBase58',
 | 
			
		||||
      'publicKeyPem': 'sec:publicKeyPem',
 | 
			
		||||
      'publicKeyWif': 'sec:publicKeyWif',
 | 
			
		||||
      'publicKeyService': { '@id': 'sec:publicKeyService', '@type': '@id' },
 | 
			
		||||
      'revoked': { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
 | 
			
		||||
      'salt': 'sec:salt',
 | 
			
		||||
      'signature': 'sec:signature',
 | 
			
		||||
      'signatureAlgorithm': 'sec:signingAlgorithm',
 | 
			
		||||
      'signatureValue': 'sec:signatureValue'
 | 
			
		||||
      authenticationTag: 'sec:authenticationTag',
 | 
			
		||||
      canonicalizationAlgorithm: 'sec:canonicalizationAlgorithm',
 | 
			
		||||
      cipherAlgorithm: 'sec:cipherAlgorithm',
 | 
			
		||||
      cipherData: 'sec:cipherData',
 | 
			
		||||
      cipherKey: 'sec:cipherKey',
 | 
			
		||||
      created: { '@id': 'dc:created', '@type': 'xsd:dateTime' },
 | 
			
		||||
      creator: { '@id': 'dc:creator', '@type': '@id' },
 | 
			
		||||
      digestAlgorithm: 'sec:digestAlgorithm',
 | 
			
		||||
      digestValue: 'sec:digestValue',
 | 
			
		||||
      domain: 'sec:domain',
 | 
			
		||||
      encryptionKey: 'sec:encryptionKey',
 | 
			
		||||
      expiration: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
 | 
			
		||||
      expires: { '@id': 'sec:expiration', '@type': 'xsd:dateTime' },
 | 
			
		||||
      initializationVector: 'sec:initializationVector',
 | 
			
		||||
      iterationCount: 'sec:iterationCount',
 | 
			
		||||
      nonce: 'sec:nonce',
 | 
			
		||||
      normalizationAlgorithm: 'sec:normalizationAlgorithm',
 | 
			
		||||
      owner: { '@id': 'sec:owner', '@type': '@id' },
 | 
			
		||||
      password: 'sec:password',
 | 
			
		||||
      privateKey: { '@id': 'sec:privateKey', '@type': '@id' },
 | 
			
		||||
      privateKeyPem: 'sec:privateKeyPem',
 | 
			
		||||
      publicKey: { '@id': 'sec:publicKey', '@type': '@id' },
 | 
			
		||||
      publicKeyBase58: 'sec:publicKeyBase58',
 | 
			
		||||
      publicKeyPem: 'sec:publicKeyPem',
 | 
			
		||||
      publicKeyWif: 'sec:publicKeyWif',
 | 
			
		||||
      publicKeyService: { '@id': 'sec:publicKeyService', '@type': '@id' },
 | 
			
		||||
      revoked: { '@id': 'sec:revoked', '@type': 'xsd:dateTime' },
 | 
			
		||||
      salt: 'sec:salt',
 | 
			
		||||
      signature: 'sec:signature',
 | 
			
		||||
      signatureAlgorithm: 'sec:signingAlgorithm',
 | 
			
		||||
      signatureValue: 'sec:signatureValue'
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -60,12 +60,12 @@ const nodeDocumentLoader = jsonld.documentLoaders.node()
 | 
			
		|||
const lru = new AsyncLRU({
 | 
			
		||||
  max: 10,
 | 
			
		||||
  load: (url, cb) => {
 | 
			
		||||
    if (CACHE[ url ] !== undefined) {
 | 
			
		||||
    if (CACHE[url] !== undefined) {
 | 
			
		||||
      logger.debug('Using cache for JSON-LD %s.', url)
 | 
			
		||||
 | 
			
		||||
      return cb(null, {
 | 
			
		||||
        contextUrl: null,
 | 
			
		||||
        document: CACHE[ url ],
 | 
			
		||||
        document: CACHE[url],
 | 
			
		||||
        documentUrl: url
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import { isHostValid } from '../servers'
 | 
			
		|||
import { peertubeTruncate } from '@server/helpers/core-utils'
 | 
			
		||||
 | 
			
		||||
function isActorEndpointsObjectValid (endpointObject: any) {
 | 
			
		||||
  if (endpointObject && endpointObject.sharedInbox) {
 | 
			
		||||
  if (endpointObject?.sharedInbox) {
 | 
			
		||||
    return isActivityPubUrlValid(endpointObject.sharedInbox)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -101,8 +101,6 @@ function normalizeActor (actor: any) {
 | 
			
		|||
      actor.summary = null
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isValidActorHandle (handle: string) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,8 +48,6 @@ function normalizeComment (comment: any) {
 | 
			
		|||
    if (typeof comment.url === 'object') comment.url = comment.url.href || comment.url.url
 | 
			
		||||
    else comment.url = comment.id
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isCommentTypeValid (comment: any): boolean {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,13 +94,13 @@ function isFileValid (
 | 
			
		|||
  if (isArray(files)) return optional
 | 
			
		||||
 | 
			
		||||
  // Should have a file
 | 
			
		||||
  const fileArray = files[ field ]
 | 
			
		||||
  const fileArray = files[field]
 | 
			
		||||
  if (!fileArray || fileArray.length === 0) {
 | 
			
		||||
    return optional
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // The file should exist
 | 
			
		||||
  const file = fileArray[ 0 ]
 | 
			
		||||
  const file = fileArray[0]
 | 
			
		||||
  if (!file || !file.originalname) return false
 | 
			
		||||
 | 
			
		||||
  // Check size
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ function isPluginTypeValid (value: any) {
 | 
			
		|||
function isPluginNameValid (value: string) {
 | 
			
		||||
  return exists(value) &&
 | 
			
		||||
    validator.isLength(value, PLUGINS_CONSTRAINTS_FIELDS.NAME) &&
 | 
			
		||||
    validator.matches(value, /^[a-z\-]+$/)
 | 
			
		||||
    validator.matches(value, /^[a-z-]+$/)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isNpmPluginNameValid (value: string) {
 | 
			
		||||
| 
						 | 
				
			
			@ -146,8 +146,8 @@ function isPackageJSONValid (packageJSON: PluginPackageJson, pluginType: PluginT
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function isLibraryCodeValid (library: any) {
 | 
			
		||||
  return typeof library.register === 'function'
 | 
			
		||||
    && typeof library.unregister === 'function'
 | 
			
		||||
  return typeof library.register === 'function' &&
 | 
			
		||||
    typeof library.unregister === 'function'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,7 +9,8 @@ function isUserNotificationTypeValid (value: any) {
 | 
			
		|||
 | 
			
		||||
function isUserNotificationSettingValid (value: any) {
 | 
			
		||||
  return exists(value) &&
 | 
			
		||||
    validator.isInt('' + value) && (
 | 
			
		||||
    validator.isInt('' + value) &&
 | 
			
		||||
    (
 | 
			
		||||
      value === UserNotificationSettingValue.NONE ||
 | 
			
		||||
      value === UserNotificationSettingValue.WEB ||
 | 
			
		||||
      value === UserNotificationSettingValue.EMAIL ||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,6 @@
 | 
			
		|||
import { Response } from 'express'
 | 
			
		||||
import validator from 'validator'
 | 
			
		||||
import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
 | 
			
		||||
import { exists } from './misc'
 | 
			
		||||
import { VideoAbuseModel } from '../../models/video/video-abuse'
 | 
			
		||||
 | 
			
		||||
const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +13,7 @@ function isVideoAbuseModerationCommentValid (value: string) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function isVideoAbuseStateValid (value: string) {
 | 
			
		||||
  return exists(value) && VIDEO_ABUSE_STATES[ value ] !== undefined
 | 
			
		||||
  return exists(value) && VIDEO_ABUSE_STATES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@ import { CONSTRAINTS_FIELDS, MIMETYPES, VIDEO_LANGUAGES } from '../../initialize
 | 
			
		|||
import { exists, isFileValid } from './misc'
 | 
			
		||||
 | 
			
		||||
function isVideoCaptionLanguageValid (value: any) {
 | 
			
		||||
  return exists(value) && VIDEO_LANGUAGES[ value ] !== undefined
 | 
			
		||||
  return exists(value) && VIDEO_LANGUAGES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const videoCaptionTypes = Object.keys(MIMETYPES.VIDEO_CAPTIONS.MIMETYPE_EXT)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ function isVideoImportTargetUrlValid (url: string) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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})`)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,6 @@
 | 
			
		|||
import { exists } from './misc'
 | 
			
		||||
import validator from 'validator'
 | 
			
		||||
import { CONSTRAINTS_FIELDS, VIDEO_PLAYLIST_PRIVACIES, VIDEO_PLAYLIST_TYPES } from '../../initializers/constants'
 | 
			
		||||
import * as express from 'express'
 | 
			
		||||
import { VideoPlaylistModel } from '../../models/video/video-playlist'
 | 
			
		||||
 | 
			
		||||
const PLAYLISTS_CONSTRAINT_FIELDS = CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,7 +13,7 @@ function isVideoPlaylistDescriptionValid (value: any) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -23,7 +21,7 @@ function isVideoPlaylistTimestampValid (value: any) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function isVideoPlaylistTypeValid (value: any) {
 | 
			
		||||
  return exists(value) && VIDEO_PLAYLIST_TYPES[ value ] !== undefined
 | 
			
		||||
  return exists(value) && VIDEO_PLAYLIST_TYPES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,15 +20,15 @@ function isVideoFilterValid (filter: VideoFilter) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function isVideoCategoryValid (value: any) {
 | 
			
		||||
  return value === null || VIDEO_CATEGORIES[ value ] !== undefined
 | 
			
		||||
  return value === null || VIDEO_CATEGORIES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isVideoStateValid (value: any) {
 | 
			
		||||
  return exists(value) && VIDEO_STATES[ value ] !== undefined
 | 
			
		||||
  return exists(value) && VIDEO_STATES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isVideoLicenceValid (value: any) {
 | 
			
		||||
  return value === null || VIDEO_LICENCES[ value ] !== undefined
 | 
			
		||||
  return value === null || VIDEO_LICENCES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isVideoLanguageValid (value: any) {
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } |
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function isVideoPrivacyValid (value: number) {
 | 
			
		||||
  return VIDEO_PRIVACIES[ value ] !== undefined
 | 
			
		||||
  return VIDEO_PRIVACIES[value] !== undefined
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isScheduleVideoUpdatePrivacyValid (value: number) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
 | 
			
		|||
  if (paramNSFW === 'false') return false
 | 
			
		||||
  if (paramNSFW === 'both') return undefined
 | 
			
		||||
 | 
			
		||||
  if (res && res.locals.oauth) {
 | 
			
		||||
  if (res?.locals.oauth) {
 | 
			
		||||
    const user = res.locals.oauth.token.User
 | 
			
		||||
 | 
			
		||||
    // User does not want NSFW videos
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ function buildNSFWFilter (res?: express.Response, paramNSFW?: string) {
 | 
			
		|||
  return null
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) {
 | 
			
		||||
function cleanUpReqFiles (req: { files: { [fieldname: string]: Express.Multer.File[] } | Express.Multer.File[] }) {
 | 
			
		||||
  const files = req.files
 | 
			
		||||
 | 
			
		||||
  if (!files) return
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  for (const key of Object.keys(files)) {
 | 
			
		||||
    const file = files[ key ]
 | 
			
		||||
    const file = files[key]
 | 
			
		||||
 | 
			
		||||
    if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
 | 
			
		||||
    else deleteFileAsync(file.path)
 | 
			
		||||
| 
						 | 
				
			
			@ -65,18 +65,18 @@ function badRequest (req: express.Request, res: express.Response) {
 | 
			
		|||
 | 
			
		||||
function createReqFiles (
 | 
			
		||||
  fieldNames: string[],
 | 
			
		||||
  mimeTypes: { [ id: string ]: string },
 | 
			
		||||
  destinations: { [ fieldName: string ]: string }
 | 
			
		||||
  mimeTypes: { [id: string]: string },
 | 
			
		||||
  destinations: { [fieldName: string]: string }
 | 
			
		||||
) {
 | 
			
		||||
  const storage = multer.diskStorage({
 | 
			
		||||
    destination: (req, file, cb) => {
 | 
			
		||||
      cb(null, destinations[ file.fieldname ])
 | 
			
		||||
      cb(null, destinations[file.fieldname])
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    filename: async (req, file, cb) => {
 | 
			
		||||
      let extension: string
 | 
			
		||||
      const fileExtension = extname(file.originalname)
 | 
			
		||||
      const extensionFromMimetype = mimeTypes[ file.mimetype ]
 | 
			
		||||
      const extensionFromMimetype = mimeTypes[file.mimetype]
 | 
			
		||||
 | 
			
		||||
      // Take the file extension if we don't understand the mime type
 | 
			
		||||
      // We have the OGG/OGV exception too because firefox sends a bad mime type when sending an OGG file
 | 
			
		||||
| 
						 | 
				
			
			@ -99,7 +99,7 @@ function createReqFiles (
 | 
			
		|||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  let fields: { name: string, maxCount: number }[] = []
 | 
			
		||||
  const fields: { name: string, maxCount: number }[] = []
 | 
			
		||||
  for (const fieldName of fieldNames) {
 | 
			
		||||
    fields.push({
 | 
			
		||||
      name: fieldName,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import * as ffmpeg from 'fluent-ffmpeg'
 | 
			
		||||
import { dirname, join } from 'path'
 | 
			
		||||
import { getTargetBitrate, getMaxBitrate, VideoResolution } from '../../shared/models/videos'
 | 
			
		||||
import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos'
 | 
			
		||||
import { FFMPEG_NICE, VIDEO_TRANSCODING_FPS } from '../initializers/constants'
 | 
			
		||||
import { processImage } from './image-utils'
 | 
			
		||||
import { logger } from './logger'
 | 
			
		||||
| 
						 | 
				
			
			@ -8,6 +8,71 @@ import { checkFFmpegEncoders } from '../initializers/checker-before-init'
 | 
			
		|||
import { readFile, remove, writeFile } from 'fs-extra'
 | 
			
		||||
import { CONFIG } from '../initializers/config'
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A toolbox to play with audio
 | 
			
		||||
 */
 | 
			
		||||
namespace audio {
 | 
			
		||||
  export const get = (videoPath: string) => {
 | 
			
		||||
    // without position, ffprobe considers the last input only
 | 
			
		||||
    // we make it consider the first input only
 | 
			
		||||
    // if you pass a file path to pos, then ffprobe acts on that file directly
 | 
			
		||||
    return new Promise<{ absolutePath: string, audioStream?: any }>((res, rej) => {
 | 
			
		||||
 | 
			
		||||
      function parseFfprobe (err: any, data: ffmpeg.FfprobeData) {
 | 
			
		||||
        if (err) return rej(err)
 | 
			
		||||
 | 
			
		||||
        if ('streams' in data) {
 | 
			
		||||
          const audioStream = data.streams.find(stream => stream['codec_type'] === 'audio')
 | 
			
		||||
          if (audioStream) {
 | 
			
		||||
            return res({
 | 
			
		||||
              absolutePath: data.format.filename,
 | 
			
		||||
              audioStream
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return res({ absolutePath: data.format.filename })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return ffmpeg.ffprobe(videoPath, parseFfprobe)
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  export namespace bitrate {
 | 
			
		||||
    const baseKbitrate = 384
 | 
			
		||||
 | 
			
		||||
    const toBits = (kbits: number) => kbits * 8000
 | 
			
		||||
 | 
			
		||||
    export const aac = (bitrate: number): number => {
 | 
			
		||||
      switch (true) {
 | 
			
		||||
        case bitrate > toBits(baseKbitrate):
 | 
			
		||||
          return baseKbitrate
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
          return -1 // we interpret it as a signal to copy the audio stream as is
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    export const mp3 = (bitrate: number): number => {
 | 
			
		||||
      /*
 | 
			
		||||
      a 192kbit/sec mp3 doesn't hold as much information as a 192kbit/sec aac.
 | 
			
		||||
      That's why, when using aac, we can go to lower kbit/sec. The equivalences
 | 
			
		||||
      made here are not made to be accurate, especially with good mp3 encoders.
 | 
			
		||||
      */
 | 
			
		||||
      switch (true) {
 | 
			
		||||
        case bitrate <= toBits(192):
 | 
			
		||||
          return 128
 | 
			
		||||
 | 
			
		||||
        case bitrate <= toBits(384):
 | 
			
		||||
          return 256
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
          return baseKbitrate
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function computeResolutionsToTranscode (videoFileHeight: number) {
 | 
			
		||||
  const resolutionsEnabled: number[] = []
 | 
			
		||||
  const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +89,7 @@ function computeResolutionsToTranscode (videoFileHeight: number) {
 | 
			
		|||
  ]
 | 
			
		||||
 | 
			
		||||
  for (const resolution of resolutions) {
 | 
			
		||||
    if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) {
 | 
			
		||||
    if (configResolutions[resolution + 'p'] === true && videoFileHeight > resolution) {
 | 
			
		||||
      resolutionsEnabled.push(resolution)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -48,9 +113,9 @@ async function getVideoStreamCodec (path: string) {
 | 
			
		|||
  const videoCodec = videoStream.codec_tag_string
 | 
			
		||||
 | 
			
		||||
  const baseProfileMatrix = {
 | 
			
		||||
    'High': '6400',
 | 
			
		||||
    'Main': '4D40',
 | 
			
		||||
    'Baseline': '42E0'
 | 
			
		||||
    High: '6400',
 | 
			
		||||
    Main: '4D40',
 | 
			
		||||
    Baseline: '42E0'
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  let baseProfile = baseProfileMatrix[videoStream.profile]
 | 
			
		||||
| 
						 | 
				
			
			@ -91,7 +156,7 @@ async function getVideoFileFPS (path: string) {
 | 
			
		|||
  if (videoStream === null) return 0
 | 
			
		||||
 | 
			
		||||
  for (const key of [ 'avg_frame_rate', 'r_frame_rate' ]) {
 | 
			
		||||
    const valuesText: string = videoStream[ key ]
 | 
			
		||||
    const valuesText: string = videoStream[key]
 | 
			
		||||
    if (!valuesText) continue
 | 
			
		||||
 | 
			
		||||
    const [ frames, seconds ] = valuesText.split('/')
 | 
			
		||||
| 
						 | 
				
			
			@ -191,7 +256,8 @@ interface OnlyAudioTranscodeOptions extends BaseTranscodeOptions {
 | 
			
		|||
  type: 'only-audio'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type TranscodeOptions = HLSTranscodeOptions
 | 
			
		||||
type TranscodeOptions =
 | 
			
		||||
  HLSTranscodeOptions
 | 
			
		||||
  | VideoTranscodeOptions
 | 
			
		||||
  | MergeAudioTranscodeOptions
 | 
			
		||||
  | OnlyAudioTranscodeOptions
 | 
			
		||||
| 
						 | 
				
			
			@ -204,13 +270,13 @@ function transcode (options: TranscodeOptions) {
 | 
			
		|||
        .output(options.outputPath)
 | 
			
		||||
 | 
			
		||||
      if (options.type === 'quick-transcode') {
 | 
			
		||||
        command = await buildQuickTranscodeCommand(command)
 | 
			
		||||
        command = buildQuickTranscodeCommand(command)
 | 
			
		||||
      } else if (options.type === 'hls') {
 | 
			
		||||
        command = await buildHLSCommand(command, options)
 | 
			
		||||
      } else if (options.type === 'merge-audio') {
 | 
			
		||||
        command = await buildAudioMergeCommand(command, options)
 | 
			
		||||
      } else if (options.type === 'only-audio') {
 | 
			
		||||
        command = await buildOnlyAudioCommand(command, options)
 | 
			
		||||
        command = buildOnlyAudioCommand(command, options)
 | 
			
		||||
      } else {
 | 
			
		||||
        command = await buildx264Command(command, options)
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -247,17 +313,17 @@ async function canDoQuickTranscode (path: string): Promise<boolean> {
 | 
			
		|||
 | 
			
		||||
  // check video params
 | 
			
		||||
  if (videoStream == null) return false
 | 
			
		||||
  if (videoStream[ 'codec_name' ] !== 'h264') return false
 | 
			
		||||
  if (videoStream[ 'pix_fmt' ] !== 'yuv420p') return false
 | 
			
		||||
  if (videoStream['codec_name'] !== 'h264') return false
 | 
			
		||||
  if (videoStream['pix_fmt'] !== 'yuv420p') return false
 | 
			
		||||
  if (fps < VIDEO_TRANSCODING_FPS.MIN || fps > VIDEO_TRANSCODING_FPS.MAX) return false
 | 
			
		||||
  if (bitRate > getMaxBitrate(resolution.videoFileResolution, fps, VIDEO_TRANSCODING_FPS)) return false
 | 
			
		||||
 | 
			
		||||
  // check audio params (if audio stream exists)
 | 
			
		||||
  if (parsedAudio.audioStream) {
 | 
			
		||||
    if (parsedAudio.audioStream[ 'codec_name' ] !== 'aac') return false
 | 
			
		||||
    if (parsedAudio.audioStream['codec_name'] !== 'aac') return false
 | 
			
		||||
 | 
			
		||||
    const maxAudioBitrate = audio.bitrate[ 'aac' ](parsedAudio.audioStream[ 'bit_rate' ])
 | 
			
		||||
    if (maxAudioBitrate !== -1 && parsedAudio.audioStream[ 'bit_rate' ] > maxAudioBitrate) return false
 | 
			
		||||
    const maxAudioBitrate = audio.bitrate['aac'](parsedAudio.audioStream['bit_rate'])
 | 
			
		||||
    if (maxAudioBitrate !== -1 && parsedAudio.audioStream['bit_rate'] > maxAudioBitrate) return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true
 | 
			
		||||
| 
						 | 
				
			
			@ -333,14 +399,14 @@ async function buildAudioMergeCommand (command: ffmpeg.FfmpegCommand, options: M
 | 
			
		|||
  return command
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
 | 
			
		||||
  command = await presetOnlyAudio(command)
 | 
			
		||||
function buildOnlyAudioCommand (command: ffmpeg.FfmpegCommand, options: OnlyAudioTranscodeOptions) {
 | 
			
		||||
  command = presetOnlyAudio(command)
 | 
			
		||||
 | 
			
		||||
  return command
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
 | 
			
		||||
  command = await presetCopy(command)
 | 
			
		||||
function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
 | 
			
		||||
  command = presetCopy(command)
 | 
			
		||||
 | 
			
		||||
  command = command.outputOption('-map_metadata -1') // strip all metadata
 | 
			
		||||
                   .outputOption('-movflags faststart')
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +417,7 @@ async function buildQuickTranscodeCommand (command: ffmpeg.FfmpegCommand) {
 | 
			
		|||
async function buildHLSCommand (command: ffmpeg.FfmpegCommand, options: HLSTranscodeOptions) {
 | 
			
		||||
  const videoPath = getHLSVideoPath(options)
 | 
			
		||||
 | 
			
		||||
  if (options.copyCodecs) command = await presetCopy(command)
 | 
			
		||||
  if (options.copyCodecs) command = presetCopy(command)
 | 
			
		||||
  else command = await buildx264Command(command, options)
 | 
			
		||||
 | 
			
		||||
  command = command.outputOption('-hls_time 4')
 | 
			
		||||
| 
						 | 
				
			
			@ -418,71 +484,6 @@ async function presetH264VeryFast (command: ffmpeg.FfmpegCommand, input: string,
 | 
			
		|||
  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.
 | 
			
		||||
 *
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
    localCommand = localCommand.audioCodec('aac')
 | 
			
		||||
 | 
			
		||||
    const audioCodecName = parsedAudio.audioStream[ 'codec_name' ]
 | 
			
		||||
    const audioCodecName = parsedAudio.audioStream['codec_name']
 | 
			
		||||
 | 
			
		||||
    if (audio.bitrate[ audioCodecName ]) {
 | 
			
		||||
      const bitrate = audio.bitrate[ audioCodecName ](parsedAudio.audioStream[ 'bit_rate' ])
 | 
			
		||||
    if (audio.bitrate[audioCodecName]) {
 | 
			
		||||
      const bitrate = audio.bitrate[audioCodecName](parsedAudio.audioStream['bit_rate'])
 | 
			
		||||
      if (bitrate !== undefined && bitrate !== -1) localCommand = localCommand.audioBitrate(bitrate)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -537,14 +538,14 @@ async function presetH264 (command: ffmpeg.FfmpegCommand, input: string, resolut
 | 
			
		|||
  return localCommand
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function presetCopy (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
 | 
			
		||||
function presetCopy (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
 | 
			
		||||
  return command
 | 
			
		||||
    .format('mp4')
 | 
			
		||||
    .videoCodec('copy')
 | 
			
		||||
    .audioCodec('copy')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function presetOnlyAudio (command: ffmpeg.FfmpegCommand): Promise<ffmpeg.FfmpegCommand> {
 | 
			
		||||
function presetOnlyAudio (command: ffmpeg.FfmpegCommand): ffmpeg.FfmpegCommand {
 | 
			
		||||
  return command
 | 
			
		||||
    .format('mp4')
 | 
			
		||||
    .audioCodec('copy')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,7 +27,7 @@ function getLoggerReplacer () {
 | 
			
		|||
    if (value instanceof Error) {
 | 
			
		||||
      const error = {}
 | 
			
		||||
 | 
			
		||||
      Object.getOwnPropertyNames(value).forEach(key => error[ key ] = value[ key ])
 | 
			
		||||
      Object.getOwnPropertyNames(value).forEach(key => { error[key] = value[key] })
 | 
			
		||||
 | 
			
		||||
      return error
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -98,19 +98,20 @@ function bunyanLogFactory (level: string) {
 | 
			
		|||
    let args: any[] = []
 | 
			
		||||
    args.concat(arguments)
 | 
			
		||||
 | 
			
		||||
    if (arguments[ 0 ] instanceof Error) {
 | 
			
		||||
      meta = arguments[ 0 ].toString()
 | 
			
		||||
    if (arguments[0] instanceof Error) {
 | 
			
		||||
      meta = arguments[0].toString()
 | 
			
		||||
      args = Array.prototype.slice.call(arguments, 1)
 | 
			
		||||
      args.push(meta)
 | 
			
		||||
    } else if (typeof (args[ 0 ]) !== 'string') {
 | 
			
		||||
      meta = arguments[ 0 ]
 | 
			
		||||
    } else if (typeof (args[0]) !== 'string') {
 | 
			
		||||
      meta = arguments[0]
 | 
			
		||||
      args = Array.prototype.slice.call(arguments, 1)
 | 
			
		||||
      args.push(meta)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    logger[ level ].apply(logger, args)
 | 
			
		||||
    logger[level].apply(logger, args)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const bunyanLogger = {
 | 
			
		||||
  trace: bunyanLogFactory('debug'),
 | 
			
		||||
  debug: bunyanLogFactory('debug'),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
// Thanks to https://regex101.com
 | 
			
		||||
function regexpCapture (str: string, regex: RegExp, maxIterations = 100) {
 | 
			
		||||
  const result: RegExpExecArray[] = []
 | 
			
		||||
  let m: RegExpExecArray
 | 
			
		||||
  let i = 0
 | 
			
		||||
  let result: RegExpExecArray[] = []
 | 
			
		||||
 | 
			
		||||
  // tslint:disable:no-conditional-assignment
 | 
			
		||||
  while ((m = regex.exec(str)) !== null && i < maxIterations) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
import { resolve } from 'path'
 | 
			
		||||
const tsConfigPaths = require('tsconfig-paths')
 | 
			
		||||
import tsConfigPaths = require('tsconfig-paths')
 | 
			
		||||
 | 
			
		||||
const tsConfig = require('../../tsconfig.json')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ async function isSignupAllowed (): Promise<{ allowed: boolean, errorMessage?: st
 | 
			
		|||
 | 
			
		||||
function isSignupAllowedForCurrentIP (ip: string) {
 | 
			
		||||
  const addr = ipaddr.parse(ip)
 | 
			
		||||
  let excludeList = [ 'blacklist' ]
 | 
			
		||||
  const excludeList = [ 'blacklist' ]
 | 
			
		||||
  let matched = ''
 | 
			
		||||
 | 
			
		||||
  // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,6 @@
 | 
			
		|||
import { ResultList } from '../../shared'
 | 
			
		||||
import { ApplicationModel } from '../models/application/application'
 | 
			
		||||
import { execPromise, execPromise2, pseudoRandomBytesPromise, sha256 } from './core-utils'
 | 
			
		||||
import { execPromise, execPromise2, randomBytesPromise, sha256 } from './core-utils'
 | 
			
		||||
import { logger } from './logger'
 | 
			
		||||
import { join } from 'path'
 | 
			
		||||
import { Instance as ParseTorrent } from 'parse-torrent'
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,7 @@ function deleteFileAsync (path: string) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
async function generateRandomString (size: number) {
 | 
			
		||||
  const raw = await pseudoRandomBytesPromise(size)
 | 
			
		||||
  const raw = await randomBytesPromise(size)
 | 
			
		||||
 | 
			
		||||
  return raw.toString('hex')
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
 | 
			
		|||
      if (torrent.files.length !== 1) {
 | 
			
		||||
        if (timer) clearTimeout(timer)
 | 
			
		||||
 | 
			
		||||
        for (let file of torrent.files) {
 | 
			
		||||
        for (const file of torrent.files) {
 | 
			
		||||
          deleteDownloadedFile({ directoryPath, filepath: file.path })
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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')))
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      file = torrent.files[ 0 ]
 | 
			
		||||
      file = torrent.files[0]
 | 
			
		||||
 | 
			
		||||
      // FIXME: avoid creating another stream when https://github.com/webtorrent/webtorrent/issues/1517 is fixed
 | 
			
		||||
      const writeStream = createWriteStream(path)
 | 
			
		||||
      writeStream.on('finish', () => {
 | 
			
		||||
        if (timer) clearTimeout(timer)
 | 
			
		||||
 | 
			
		||||
        return safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName)
 | 
			
		||||
        safeWebtorrentDestroy(webtorrent, torrentId, { directoryPath, filepath: file.path }, target.torrentName)
 | 
			
		||||
          .then(() => res(path))
 | 
			
		||||
          .catch(err => logger.error('Cannot destroy webtorrent.', { err }))
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      file.createReadStream().pipe(writeStream)
 | 
			
		||||
| 
						 | 
				
			
			@ -63,9 +64,16 @@ async function downloadWebTorrentVideo (target: { magnetUri: string, torrentName
 | 
			
		|||
 | 
			
		||||
    torrent.on('error', err => rej(err))
 | 
			
		||||
 | 
			
		||||
    timer = setTimeout(async () => {
 | 
			
		||||
      return safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName)
 | 
			
		||||
        .then(() => rej(new Error('Webtorrent download timeout.')))
 | 
			
		||||
    timer = setTimeout(() => {
 | 
			
		||||
      const err = new Error('Webtorrent download timeout.')
 | 
			
		||||
 | 
			
		||||
      safeWebtorrentDestroy(webtorrent, torrentId, file ? { directoryPath, filepath: file.path } : undefined, target.torrentName)
 | 
			
		||||
        .then(() => rej(err))
 | 
			
		||||
        .catch(destroyErr => {
 | 
			
		||||
          logger.error('Cannot destroy webtorrent.', { err: destroyErr })
 | 
			
		||||
          rej(err)
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    }, timeout)
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,20 +24,23 @@ const processOptions = {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
function getYoutubeDLInfo (url: string, opts?: string[]): Promise<YoutubeDLInfo> {
 | 
			
		||||
  return new Promise<YoutubeDLInfo>(async (res, rej) => {
 | 
			
		||||
  return new Promise<YoutubeDLInfo>((res, rej) => {
 | 
			
		||||
    let args = opts || [ '-j', '--flat-playlist' ]
 | 
			
		||||
    args = wrapWithProxyOptions(args)
 | 
			
		||||
 | 
			
		||||
    const youtubeDL = await safeGetYoutubeDL()
 | 
			
		||||
    youtubeDL.getInfo(url, args, processOptions, (err, info) => {
 | 
			
		||||
      if (err) return rej(err)
 | 
			
		||||
      if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
 | 
			
		||||
    safeGetYoutubeDL()
 | 
			
		||||
      .then(youtubeDL => {
 | 
			
		||||
        youtubeDL.getInfo(url, args, processOptions, (err, info) => {
 | 
			
		||||
          if (err) return rej(err)
 | 
			
		||||
          if (info.is_live === true) return rej(new Error('Cannot download a live streaming.'))
 | 
			
		||||
 | 
			
		||||
      const obj = buildVideoInfo(normalizeObject(info))
 | 
			
		||||
      if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video'
 | 
			
		||||
          const obj = buildVideoInfo(normalizeObject(info))
 | 
			
		||||
          if (obj.name && obj.name.length < CONSTRAINTS_FIELDS.VIDEOS.NAME.min) obj.name += ' video'
 | 
			
		||||
 | 
			
		||||
      return res(obj)
 | 
			
		||||
    })
 | 
			
		||||
          return res(obj)
 | 
			
		||||
        })
 | 
			
		||||
      })
 | 
			
		||||
      .catch(err => rej(err))
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -54,26 +57,34 @@ function downloadYoutubeDLVideo (url: string, timeout: number) {
 | 
			
		|||
    options = options.concat([ '--ffmpeg-location', process.env.FFMPEG_PATH ])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return new Promise<string>(async (res, rej) => {
 | 
			
		||||
    const youtubeDL = await safeGetYoutubeDL()
 | 
			
		||||
    youtubeDL.exec(url, options, processOptions, err => {
 | 
			
		||||
      clearTimeout(timer)
 | 
			
		||||
  return new Promise<string>((res, rej) => {
 | 
			
		||||
    safeGetYoutubeDL()
 | 
			
		||||
      .then(youtubeDL => {
 | 
			
		||||
        youtubeDL.exec(url, options, processOptions, err => {
 | 
			
		||||
          clearTimeout(timer)
 | 
			
		||||
 | 
			
		||||
      if (err) {
 | 
			
		||||
        remove(path)
 | 
			
		||||
          .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err }))
 | 
			
		||||
          if (err) {
 | 
			
		||||
            remove(path)
 | 
			
		||||
              .catch(err => logger.error('Cannot delete path on YoutubeDL error.', { err }))
 | 
			
		||||
 | 
			
		||||
        return rej(err)
 | 
			
		||||
      }
 | 
			
		||||
            return rej(err)
 | 
			
		||||
          }
 | 
			
		||||
 | 
			
		||||
      return res(path)
 | 
			
		||||
    })
 | 
			
		||||
          return res(path)
 | 
			
		||||
        })
 | 
			
		||||
 | 
			
		||||
    timer = setTimeout(async () => {
 | 
			
		||||
      await remove(path)
 | 
			
		||||
        timer = setTimeout(() => {
 | 
			
		||||
          const err = new Error('YoutubeDL download timeout.')
 | 
			
		||||
 | 
			
		||||
      return rej(new Error('YoutubeDL download timeout.'))
 | 
			
		||||
    }, timeout)
 | 
			
		||||
          remove(path)
 | 
			
		||||
            .finally(() => rej(err))
 | 
			
		||||
            .catch(err => {
 | 
			
		||||
              logger.error('Cannot remove %s in youtubeDL timeout.', path, { err })
 | 
			
		||||
              return rej(err)
 | 
			
		||||
            })
 | 
			
		||||
        }, timeout)
 | 
			
		||||
      })
 | 
			
		||||
      .catch(err => rej(err))
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -103,7 +114,7 @@ async function updateYoutubeDLBinary () {
 | 
			
		|||
 | 
			
		||||
      const url = result.headers.location
 | 
			
		||||
      const downloadFile = request.get(url)
 | 
			
		||||
      const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[ 1 ]
 | 
			
		||||
      const newVersion = /yt-dl\.org\/downloads\/(\d{4}\.\d\d\.\d\d(\.\d)?)\/youtube-dl/.exec(url)[1]
 | 
			
		||||
 | 
			
		||||
      downloadFile.on('response', result => {
 | 
			
		||||
        if (result.statusCode !== 200) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@ import { isProdInstance, isTestInstance } from '../helpers/core-utils'
 | 
			
		|||
import { UserModel } from '../models/account/user'
 | 
			
		||||
import { ApplicationModel } from '../models/application/application'
 | 
			
		||||
import { OAuthClientModel } from '../models/oauth/oauth-client'
 | 
			
		||||
import { parse } from 'url'
 | 
			
		||||
import { URL } from 'url'
 | 
			
		||||
import { CONFIG } from './config'
 | 
			
		||||
import { logger } from '../helpers/logger'
 | 
			
		||||
import { getServerActor } from '../helpers/utils'
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,7 @@ import { WEBSERVER } from './constants'
 | 
			
		|||
async function checkActivityPubUrls () {
 | 
			
		||||
  const actor = await getServerActor()
 | 
			
		||||
 | 
			
		||||
  const parsed = parse(actor.url)
 | 
			
		||||
  const parsed = new URL(actor.url)
 | 
			
		||||
  if (WEBSERVER.HOST !== parsed.host) {
 | 
			
		||||
    const NODE_ENV = config.util.getEnv('NODE_ENV')
 | 
			
		||||
    const NODE_CONFIG_DIR = config.util.getEnv('NODE_CONFIG_DIR')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,8 +35,8 @@ function checkMissedConfig () {
 | 
			
		|||
  ]
 | 
			
		||||
  const requiredAlternatives = [
 | 
			
		||||
    [ // set
 | 
			
		||||
      ['redis.hostname', 'redis.port'], // alternative
 | 
			
		||||
      ['redis.socket']
 | 
			
		||||
      [ 'redis.hostname', 'redis.port' ], // alternative
 | 
			
		||||
      [ 'redis.socket' ]
 | 
			
		||||
    ]
 | 
			
		||||
  ]
 | 
			
		||||
  const miss: string[] = []
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -301,7 +301,7 @@ function getLocalConfigFilePath () {
 | 
			
		|||
  if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
 | 
			
		||||
  if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
 | 
			
		||||
 | 
			
		||||
  return join(dirname(configSources[ 0 ].name), filename + '.json')
 | 
			
		||||
  return join(dirname(configSources[0].name), filename + '.json')
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
 | 
			
		||||
| 
						 | 
				
			
			@ -330,7 +330,7 @@ export function reloadConfig () {
 | 
			
		|||
 | 
			
		||||
  function purge () {
 | 
			
		||||
    for (const fileName in require.cache) {
 | 
			
		||||
      if (-1 === fileName.indexOf(directory())) {
 | 
			
		||||
      if (fileName.indexOf(directory()) === -1) {
 | 
			
		||||
        continue
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ import { ActivityPubActorType } from '../../shared/models/activitypub'
 | 
			
		|||
import { FollowState } from '../../shared/models/actors'
 | 
			
		||||
import { VideoAbuseState, VideoImportState, VideoPrivacy, VideoTranscodingFPS } from '../../shared/models/videos'
 | 
			
		||||
// Do not use barrels, remain constants as independent as possible
 | 
			
		||||
import { isTestInstance, sanitizeHost, sanitizeUrl, root, parseDurationToMs } from '../helpers/core-utils'
 | 
			
		||||
import { isTestInstance, sanitizeHost, sanitizeUrl, root } from '../helpers/core-utils'
 | 
			
		||||
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
 | 
			
		||||
import { invert } from 'lodash'
 | 
			
		||||
import { CronRepeatOptions, EveryRepeatOptions } from 'bull'
 | 
			
		||||
| 
						 | 
				
			
			@ -310,8 +310,8 @@ let CONTACT_FORM_LIFETIME = 60000 * 60 // 1 hour
 | 
			
		|||
 | 
			
		||||
const VIDEO_TRANSCODING_FPS: VideoTranscodingFPS = {
 | 
			
		||||
  MIN: 10,
 | 
			
		||||
  STANDARD: [24, 25, 30],
 | 
			
		||||
  HD_STANDARD: [50, 60],
 | 
			
		||||
  STANDARD: [ 24, 25, 30 ],
 | 
			
		||||
  HD_STANDARD: [ 50, 60 ],
 | 
			
		||||
  AVERAGE: 30,
 | 
			
		||||
  MAX: 60,
 | 
			
		||||
  KEEP_ORIGIN_FPS_RESOLUTION_MIN: 720 // We keep the original FPS on high resolutions (720 minimum)
 | 
			
		||||
| 
						 | 
				
			
			@ -361,42 +361,42 @@ const VIDEO_LICENCES = {
 | 
			
		|||
  7: 'Public Domain Dedication'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let VIDEO_LANGUAGES: { [id: string]: string } = {}
 | 
			
		||||
const VIDEO_LANGUAGES: { [id: string]: string } = {}
 | 
			
		||||
 | 
			
		||||
const VIDEO_PRIVACIES = {
 | 
			
		||||
  [ VideoPrivacy.PUBLIC ]: 'Public',
 | 
			
		||||
  [ VideoPrivacy.UNLISTED ]: 'Unlisted',
 | 
			
		||||
  [ VideoPrivacy.PRIVATE ]: 'Private',
 | 
			
		||||
  [ VideoPrivacy.INTERNAL ]: 'Internal'
 | 
			
		||||
  [VideoPrivacy.PUBLIC]: 'Public',
 | 
			
		||||
  [VideoPrivacy.UNLISTED]: 'Unlisted',
 | 
			
		||||
  [VideoPrivacy.PRIVATE]: 'Private',
 | 
			
		||||
  [VideoPrivacy.INTERNAL]: 'Internal'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VIDEO_STATES = {
 | 
			
		||||
  [ VideoState.PUBLISHED ]: 'Published',
 | 
			
		||||
  [ VideoState.TO_TRANSCODE ]: 'To transcode',
 | 
			
		||||
  [ VideoState.TO_IMPORT ]: 'To import'
 | 
			
		||||
  [VideoState.PUBLISHED]: 'Published',
 | 
			
		||||
  [VideoState.TO_TRANSCODE]: 'To transcode',
 | 
			
		||||
  [VideoState.TO_IMPORT]: 'To import'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VIDEO_IMPORT_STATES = {
 | 
			
		||||
  [ VideoImportState.FAILED ]: 'Failed',
 | 
			
		||||
  [ VideoImportState.PENDING ]: 'Pending',
 | 
			
		||||
  [ VideoImportState.SUCCESS ]: 'Success'
 | 
			
		||||
  [VideoImportState.FAILED]: 'Failed',
 | 
			
		||||
  [VideoImportState.PENDING]: 'Pending',
 | 
			
		||||
  [VideoImportState.SUCCESS]: 'Success'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VIDEO_ABUSE_STATES = {
 | 
			
		||||
  [ VideoAbuseState.PENDING ]: 'Pending',
 | 
			
		||||
  [ VideoAbuseState.REJECTED ]: 'Rejected',
 | 
			
		||||
  [ VideoAbuseState.ACCEPTED ]: 'Accepted'
 | 
			
		||||
  [VideoAbuseState.PENDING]: 'Pending',
 | 
			
		||||
  [VideoAbuseState.REJECTED]: 'Rejected',
 | 
			
		||||
  [VideoAbuseState.ACCEPTED]: 'Accepted'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VIDEO_PLAYLIST_PRIVACIES = {
 | 
			
		||||
  [ VideoPlaylistPrivacy.PUBLIC ]: 'Public',
 | 
			
		||||
  [ VideoPlaylistPrivacy.UNLISTED ]: 'Unlisted',
 | 
			
		||||
  [ VideoPlaylistPrivacy.PRIVATE ]: 'Private'
 | 
			
		||||
  [VideoPlaylistPrivacy.PUBLIC]: 'Public',
 | 
			
		||||
  [VideoPlaylistPrivacy.UNLISTED]: 'Unlisted',
 | 
			
		||||
  [VideoPlaylistPrivacy.PRIVATE]: 'Private'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const VIDEO_PLAYLIST_TYPES = {
 | 
			
		||||
  [ VideoPlaylistType.REGULAR ]: 'Regular',
 | 
			
		||||
  [ VideoPlaylistType.WATCH_LATER ]: 'Watch later'
 | 
			
		||||
  [VideoPlaylistType.REGULAR]: 'Regular',
 | 
			
		||||
  [VideoPlaylistType.WATCH_LATER]: 'Watch later'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const MIMETYPES = {
 | 
			
		||||
| 
						 | 
				
			
			@ -533,7 +533,7 @@ const LAZY_STATIC_PATHS = {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
// Cache control
 | 
			
		||||
let STATIC_MAX_AGE = {
 | 
			
		||||
const STATIC_MAX_AGE = {
 | 
			
		||||
  SERVER: '2h',
 | 
			
		||||
  CLIENT: '30d'
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -671,14 +671,14 @@ if (isTestInstance() === true) {
 | 
			
		|||
  SCHEDULER_INTERVALS_MS.removeOldViews = 5000
 | 
			
		||||
  SCHEDULER_INTERVALS_MS.updateVideos = 5000
 | 
			
		||||
  SCHEDULER_INTERVALS_MS.autoFollowIndexInstances = 5000
 | 
			
		||||
  REPEAT_JOBS[ 'videos-views' ] = { every: 5000 }
 | 
			
		||||
  REPEAT_JOBS['videos-views'] = { every: 5000 }
 | 
			
		||||
 | 
			
		||||
  REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR = 1
 | 
			
		||||
 | 
			
		||||
  VIDEO_VIEW_LIFETIME = 1000 // 1 second
 | 
			
		||||
  CONTACT_FORM_LIFETIME = 1000 // 1 second
 | 
			
		||||
 | 
			
		||||
  JOB_ATTEMPTS[ 'email' ] = 1
 | 
			
		||||
  JOB_ATTEMPTS['email'] = 1
 | 
			
		||||
 | 
			
		||||
  FILES_CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000
 | 
			
		||||
  MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1
 | 
			
		||||
| 
						 | 
				
			
			@ -838,42 +838,42 @@ function loadLanguages () {
 | 
			
		|||
function buildLanguages () {
 | 
			
		||||
  const iso639 = require('iso-639-3')
 | 
			
		||||
 | 
			
		||||
  const languages: { [ id: string ]: string } = {}
 | 
			
		||||
  const languages: { [id: string]: string } = {}
 | 
			
		||||
 | 
			
		||||
  const additionalLanguages = {
 | 
			
		||||
    'sgn': true, // Sign languages (macro language)
 | 
			
		||||
    'ase': true, // American sign language
 | 
			
		||||
    'sdl': true, // Arabian sign language
 | 
			
		||||
    'bfi': true, // British sign language
 | 
			
		||||
    'bzs': true, // Brazilian sign language
 | 
			
		||||
    'csl': true, // Chinese sign language
 | 
			
		||||
    'cse': true, // Czech sign language
 | 
			
		||||
    'dsl': true, // Danish sign language
 | 
			
		||||
    'fsl': true, // French sign language
 | 
			
		||||
    'gsg': true, // German sign language
 | 
			
		||||
    'pks': true, // Pakistan sign language
 | 
			
		||||
    'jsl': true, // Japanese sign language
 | 
			
		||||
    'sfs': true, // South African sign language
 | 
			
		||||
    'swl': true, // Swedish sign language
 | 
			
		||||
    'rsl': true, // Russian sign language: true
 | 
			
		||||
    sgn: true, // Sign languages (macro language)
 | 
			
		||||
    ase: true, // American sign language
 | 
			
		||||
    sdl: true, // Arabian sign language
 | 
			
		||||
    bfi: true, // British sign language
 | 
			
		||||
    bzs: true, // Brazilian sign language
 | 
			
		||||
    csl: true, // Chinese sign language
 | 
			
		||||
    cse: true, // Czech sign language
 | 
			
		||||
    dsl: true, // Danish sign language
 | 
			
		||||
    fsl: true, // French sign language
 | 
			
		||||
    gsg: true, // German sign language
 | 
			
		||||
    pks: true, // Pakistan sign language
 | 
			
		||||
    jsl: true, // Japanese sign language
 | 
			
		||||
    sfs: true, // South African sign language
 | 
			
		||||
    swl: true, // Swedish sign language
 | 
			
		||||
    rsl: true, // Russian sign language: true
 | 
			
		||||
 | 
			
		||||
    'epo': true, // Esperanto
 | 
			
		||||
    'tlh': true, // Klingon
 | 
			
		||||
    'jbo': true, // Lojban
 | 
			
		||||
    'avk': true // Kotava
 | 
			
		||||
    epo: true, // Esperanto
 | 
			
		||||
    tlh: true, // Klingon
 | 
			
		||||
    jbo: true, // Lojban
 | 
			
		||||
    avk: true // Kotava
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Only add ISO639-1 languages and some sign languages (ISO639-3)
 | 
			
		||||
  iso639
 | 
			
		||||
    .filter(l => {
 | 
			
		||||
      return (l.iso6391 !== null && l.type === 'living') ||
 | 
			
		||||
        additionalLanguages[ l.iso6393 ] === true
 | 
			
		||||
        additionalLanguages[l.iso6393] === true
 | 
			
		||||
    })
 | 
			
		||||
    .forEach(l => languages[ l.iso6391 || l.iso6393 ] = l.name)
 | 
			
		||||
    .forEach(l => { languages[l.iso6391 || l.iso6393] = l.name })
 | 
			
		||||
 | 
			
		||||
  // Override Occitan label
 | 
			
		||||
  languages[ 'oc' ] = 'Occitan'
 | 
			
		||||
  languages[ 'el' ] = 'Greek'
 | 
			
		||||
  languages['oc'] = 'Occitan'
 | 
			
		||||
  languages['el'] = 'Greek'
 | 
			
		||||
 | 
			
		||||
  return languages
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -119,8 +119,6 @@ async function initDatabaseModels (silent: boolean) {
 | 
			
		|||
  await createFunctions()
 | 
			
		||||
 | 
			
		||||
  if (!silent) logger.info('Database %s is ready.', dbname)
 | 
			
		||||
 | 
			
		||||
  return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ---------------------------------------------------------------------------
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,9 +5,9 @@ import { VideoModel } from '../../models/video/video'
 | 
			
		|||
import { getVideoFilePath } from '@server/lib/video-paths'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  return utils.db.Video.listOwnedAndPopulateAuthorAndTags()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,9 @@ import * as Promise from 'bluebird'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,9 +5,9 @@ import { getVideoFileResolution } from '../../helpers/ffmpeg-utils'
 | 
			
		|||
import { readdir, rename } from 'fs-extra'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const torrentDir = CONFIG.STORAGE.TORRENTS_DIR
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,9 +2,9 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as uuidv4 from 'uuid/v4'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,9 +7,9 @@ import { ApplicationModel } from '../../models/application/application'
 | 
			
		|||
import { SERVER_ACTOR_NAME } from '../constants'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.removeColumn('Servers', 'email')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.removeColumn('Servers', 'publicKey')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.db.Avatar.sync()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.renameTable('Applications', 'application')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import * as Promise from 'bluebird'
 | 
			
		||||
 | 
			
		||||
function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const q = utils.queryInterface
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,8 +3,8 @@ import { DataType } from 'sequelize-typescript'
 | 
			
		|||
import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  // Create actor table
 | 
			
		||||
| 
						 | 
				
			
			@ -64,10 +64,10 @@ async function up (utils: {
 | 
			
		|||
          type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
 | 
			
		||||
        )
 | 
			
		||||
        SELECT 
 | 
			
		||||
        SELECT
 | 
			
		||||
          'Application', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 
 | 
			
		||||
        FROM account 
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
 | 
			
		||||
        FROM account
 | 
			
		||||
        WHERE "applicationId" IS NOT NULL
 | 
			
		||||
        `
 | 
			
		||||
    await utils.sequelize.query(query1)
 | 
			
		||||
| 
						 | 
				
			
			@ -79,10 +79,10 @@ async function up (utils: {
 | 
			
		|||
          type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
 | 
			
		||||
        )
 | 
			
		||||
        SELECT 
 | 
			
		||||
        SELECT
 | 
			
		||||
          'Person', uuid, name, url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt" 
 | 
			
		||||
        FROM account 
 | 
			
		||||
          "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
 | 
			
		||||
        FROM account
 | 
			
		||||
        WHERE "applicationId" IS NULL
 | 
			
		||||
        `
 | 
			
		||||
    await utils.sequelize.query(query2)
 | 
			
		||||
| 
						 | 
				
			
			@ -108,17 +108,17 @@ async function up (utils: {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  {
 | 
			
		||||
    const query = `  
 | 
			
		||||
    INSERT INTO actor 
 | 
			
		||||
    const query = `
 | 
			
		||||
    INSERT INTO actor
 | 
			
		||||
    (
 | 
			
		||||
    type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl", 
 | 
			
		||||
    type, uuid, "preferredUsername", url, "publicKey", "privateKey", "followersCount", "followingCount", "inboxUrl", "outboxUrl",
 | 
			
		||||
    "sharedInboxUrl", "followersUrl", "followingUrl", "avatarId", "serverId", "createdAt", "updatedAt"
 | 
			
		||||
    )
 | 
			
		||||
    SELECT 
 | 
			
		||||
    'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox', 
 | 
			
		||||
    SELECT
 | 
			
		||||
    'Group', "videoChannel".uuid, "videoChannel".uuid, "videoChannel".url, null, null, 0, 0, "videoChannel".url || '/inbox',
 | 
			
		||||
    "videoChannel".url || '/outbox', "videoChannel".url || '/inbox', "videoChannel".url || '/followers', "videoChannel".url || '/following',
 | 
			
		||||
     null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt" 
 | 
			
		||||
     FROM "videoChannel" 
 | 
			
		||||
     null, account."serverId", "videoChannel"."createdAt", "videoChannel"."updatedAt"
 | 
			
		||||
     FROM "videoChannel"
 | 
			
		||||
     INNER JOIN "account" on "videoChannel"."accountId" = "account".id
 | 
			
		||||
    `
 | 
			
		||||
    await utils.sequelize.query(query)
 | 
			
		||||
| 
						 | 
				
			
			@ -157,13 +157,13 @@ async function up (utils: {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    {
 | 
			
		||||
      const query1 = `UPDATE "actorFollow" 
 | 
			
		||||
      SET "actorId" = 
 | 
			
		||||
      const query1 = `UPDATE "actorFollow"
 | 
			
		||||
      SET "actorId" =
 | 
			
		||||
      (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."actorId")`
 | 
			
		||||
      await utils.sequelize.query(query1)
 | 
			
		||||
 | 
			
		||||
      const query2 = `UPDATE "actorFollow" 
 | 
			
		||||
      SET "targetActorId" = 
 | 
			
		||||
      const query2 = `UPDATE "actorFollow"
 | 
			
		||||
      SET "targetActorId" =
 | 
			
		||||
      (SELECT "account"."actorId" FROM account WHERE "account"."id" = "actorFollow"."targetActorId")`
 | 
			
		||||
 | 
			
		||||
      await utils.sequelize.query(query2)
 | 
			
		||||
| 
						 | 
				
			
			@ -189,8 +189,8 @@ async function up (utils: {
 | 
			
		|||
      await utils.queryInterface.removeConstraint('videoShare', 'videoShare_accountId_fkey')
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const query = `UPDATE "videoShare" 
 | 
			
		||||
      SET "actorId" = 
 | 
			
		||||
    const query = `UPDATE "videoShare"
 | 
			
		||||
      SET "actorId" =
 | 
			
		||||
      (SELECT "actorId" FROM account WHERE id = "videoShare"."actorId")`
 | 
			
		||||
    await utils.sequelize.query(query)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import { WEBSERVER } from '../constants'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const toReplace = WEBSERVER.HOSTNAME + ':443'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.dropTable('Authors')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.removeConstraint('actor', 'actor_avatarId_fkey')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import { Migration } from '../../models/migrations'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const data = {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import { ACTOR_FOLLOW_SCORE } from '../constants'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.removeColumn('server', 'score')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  const query = 'UPDATE "actor" SET ' +
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  await utils.queryInterface.dropTable('job')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,8 +2,8 @@ import * as Sequelize from 'sequelize'
 | 
			
		|||
import { CONSTRAINTS_FIELDS } from '../constants'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,8 +1,8 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,4 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
import { VideoAbuseState } from '../../../shared/models/videos'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,9 +1,9 @@
 | 
			
		|||
import * as Sequelize from 'sequelize'
 | 
			
		||||
 | 
			
		||||
async function up (utils: {
 | 
			
		||||
  transaction: Sequelize.Transaction,
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface,
 | 
			
		||||
  sequelize: Sequelize.Sequelize,
 | 
			
		||||
  transaction: Sequelize.Transaction
 | 
			
		||||
  queryInterface: Sequelize.QueryInterface
 | 
			
		||||
  sequelize: Sequelize.Sequelize
 | 
			
		||||
  db: any
 | 
			
		||||
}): Promise<void> {
 | 
			
		||||
  {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue