Update server dependencies
This commit is contained in:
parent
29f148a613
commit
ba5a8d89bb
28
package.json
28
package.json
|
@ -97,13 +97,13 @@
|
|||
"bull": "^3.4.2",
|
||||
"bytes": "^3.0.0",
|
||||
"chokidar": "^3.4.2",
|
||||
"commander": "^6.0.0",
|
||||
"commander": "^7.0.0",
|
||||
"config": "^3.0.0",
|
||||
"cookie-parser": "^1.4.3",
|
||||
"cors": "^2.8.1",
|
||||
"create-torrent": "^4.0.0",
|
||||
"deep-object-diff": "^1.1.0",
|
||||
"email-templates": "^7.0.4",
|
||||
"email-templates": "^8.0.3",
|
||||
"express": "^4.12.4",
|
||||
"express-oauth-server": "^2.0.0",
|
||||
"express-rate-limit": "^5.0.0",
|
||||
|
@ -118,12 +118,12 @@
|
|||
"is-cidr": "^4.0.0",
|
||||
"iso-639-3": "^2.0.0",
|
||||
"jimp": "^0.16.0",
|
||||
"js-yaml": "^3.5.4",
|
||||
"jsonld": "~3.2.0",
|
||||
"js-yaml": "^4.0.0",
|
||||
"jsonld": "~3.3.0",
|
||||
"lodash": "^4.17.10",
|
||||
"lru-cache": "^6.0.0",
|
||||
"magnet-uri": "^6.1.0",
|
||||
"markdown-it": "12.0.2",
|
||||
"markdown-it": "12.0.4",
|
||||
"markdown-it-emoji": "^2.0.0",
|
||||
"memoizee": "^0.4.14",
|
||||
"morgan": "^1.5.3",
|
||||
|
@ -143,7 +143,7 @@
|
|||
"request": "^2.81.0",
|
||||
"sanitize-html": "2.x",
|
||||
"scripty": "^2.0.0",
|
||||
"sequelize": "6.3.5",
|
||||
"sequelize": "6.5.0",
|
||||
"sequelize-typescript": "^2.0.0-beta.1",
|
||||
"sitemap": "^6.1.0",
|
||||
"socket.io": "^3.0.2",
|
||||
|
@ -155,7 +155,7 @@
|
|||
"uuid": "^8.1.0",
|
||||
"validator": "^13.0.0",
|
||||
"webfinger.js": "^2.6.6",
|
||||
"webtorrent": "^0.111.0",
|
||||
"webtorrent": "^0.112.3",
|
||||
"winston": "3.3.3",
|
||||
"ws": "^7.0.0",
|
||||
"youtube-dl": "^3.0.2"
|
||||
|
@ -168,13 +168,13 @@
|
|||
"@types/bcrypt": "^3.0.0",
|
||||
"@types/bluebird": "3.5.33",
|
||||
"@types/body-parser": "^1.16.3",
|
||||
"@types/bull": "3.14.4",
|
||||
"@types/bull": "3.15.0",
|
||||
"@types/bytes": "^3.0.0",
|
||||
"@types/chai": "^4.0.4",
|
||||
"@types/chai-json-schema": "^1.4.3",
|
||||
"@types/chai-xml": "^0.3.1",
|
||||
"@types/config": "^0.0.36",
|
||||
"@types/express": "^4.0.35",
|
||||
"@types/config": "^0.0.38",
|
||||
"@types/express": "4.17.9",
|
||||
"@types/express-rate-limit": "^5.0.0",
|
||||
"@types/fluent-ffmpeg": "^2.1.16",
|
||||
"@types/fs-extra": "^9.0.1",
|
||||
|
@ -188,7 +188,7 @@
|
|||
"@types/mocha": "^8.0.3",
|
||||
"@types/morgan": "^1.7.32",
|
||||
"@types/multer": "^1.3.3",
|
||||
"@types/node": "^14.0.13",
|
||||
"@types/node": "^12",
|
||||
"@types/nodemailer": "^6.2.0",
|
||||
"@types/oauth2-server": "^3.0.8",
|
||||
"@types/pem": "^1.9.3",
|
||||
|
@ -204,11 +204,11 @@
|
|||
"chai-xml": "^0.4.0",
|
||||
"concurrently": "^5.0.0",
|
||||
"eslint": "^7.2.0",
|
||||
"eslint-config-standard-with-typescript": "^19.0.1",
|
||||
"eslint-config-standard-with-typescript": "^20.0.0",
|
||||
"eslint-plugin-import": "^2.20.1",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"libxmljs": "0.19.7",
|
||||
"maildev": "^1.0.0-rc3",
|
||||
"marked": "^1.1.0",
|
||||
|
@ -219,7 +219,7 @@
|
|||
"source-map-support": "^0.5.0",
|
||||
"supertest": "^6.0.1",
|
||||
"swagger-cli": "^4.0.2",
|
||||
"ts-node": "9.0.0",
|
||||
"ts-node": "9.1.1",
|
||||
"typescript": "^4.0.5"
|
||||
},
|
||||
"scripty": {
|
||||
|
|
|
@ -13,7 +13,9 @@ program
|
|||
.description('Import a video file to replace an already uploaded file or to add a new resolution')
|
||||
.parse(process.argv)
|
||||
|
||||
if (program['video'] === undefined || program['import'] === undefined) {
|
||||
const options = program.opts()
|
||||
|
||||
if (options.video === undefined || options.import === undefined) {
|
||||
console.error('All parameters are mandatory.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
@ -28,13 +30,13 @@ run()
|
|||
async function run () {
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const video = await VideoModel.loadByUUID(program['video'])
|
||||
const video = await VideoModel.loadByUUID(options.video)
|
||||
if (!video) throw new Error('Video not found.')
|
||||
if (video.isOwned() === false) throw new Error('Cannot import files of a non owned video.')
|
||||
|
||||
const dataInput = {
|
||||
videoUUID: video.uuid,
|
||||
filePath: resolve(program['import'])
|
||||
filePath: resolve(options.import)
|
||||
}
|
||||
|
||||
await JobQueue.Instance.init()
|
||||
|
|
|
@ -14,12 +14,14 @@ program
|
|||
.option('--generate-hls', 'Generate HLS playlist')
|
||||
.parse(process.argv)
|
||||
|
||||
if (program['video'] === undefined) {
|
||||
const options = program.opts()
|
||||
|
||||
if (options.video === undefined) {
|
||||
console.error('All parameters are mandatory.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
if (program.resolution !== undefined && Number.isNaN(+program.resolution)) {
|
||||
if (options.resolution !== undefined && Number.isNaN(+options.resolution)) {
|
||||
console.error('The resolution must be an integer (example: 1080).')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
@ -34,15 +36,15 @@ run()
|
|||
async function run () {
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(program['video'])
|
||||
const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(options.video)
|
||||
if (!video) throw new Error('Video not found.')
|
||||
|
||||
const dataInput: VideoTranscodingPayload[] = []
|
||||
const { videoFileResolution } = await video.getMaxQualityResolution()
|
||||
|
||||
if (program.generateHls) {
|
||||
const resolutionsEnabled = program.resolution
|
||||
? [ program.resolution ]
|
||||
if (options.generateHls) {
|
||||
const resolutionsEnabled = options.resolution
|
||||
? [ options.resolution ]
|
||||
: computeResolutionsToTranscode(videoFileResolution, 'vod').concat([ videoFileResolution ])
|
||||
|
||||
for (const resolution of resolutionsEnabled) {
|
||||
|
@ -54,12 +56,12 @@ async function run () {
|
|||
copyCodecs: false
|
||||
})
|
||||
}
|
||||
} else if (program.resolution !== undefined) {
|
||||
} else if (options.resolution !== undefined) {
|
||||
dataInput.push({
|
||||
type: 'new-resolution-to-webtorrent',
|
||||
videoUUID: video.uuid,
|
||||
isNewVideo: false,
|
||||
resolution: program.resolution
|
||||
resolution: options.resolution
|
||||
})
|
||||
} else {
|
||||
dataInput.push({
|
||||
|
|
|
@ -17,6 +17,8 @@ program
|
|||
.option('-f, --files [file...]', 'Files to parse. If not provided, the script will parse the latest log file from config)')
|
||||
.parse(process.argv)
|
||||
|
||||
const options = program.opts()
|
||||
|
||||
const excludedKeys = {
|
||||
level: true,
|
||||
message: true,
|
||||
|
@ -38,7 +40,7 @@ const loggerFormat = winston.format.printf((info) => {
|
|||
if (CONFIG.LOG.PRETTIFY_SQL) {
|
||||
additionalInfos += '\n' + sqlFormat(info.sql, {
|
||||
language: 'sql',
|
||||
ident: ' '
|
||||
indent: ' '
|
||||
})
|
||||
} else {
|
||||
additionalInfos += ' - ' + info.sql
|
||||
|
@ -51,7 +53,7 @@ const loggerFormat = winston.format.printf((info) => {
|
|||
const logger = winston.createLogger({
|
||||
transports: [
|
||||
new winston.transports.Console({
|
||||
level: program['level'] || 'debug',
|
||||
level: options.level || 'debug',
|
||||
stderrLevels: [],
|
||||
format: winston.format.combine(
|
||||
winston.format.splat(),
|
||||
|
@ -76,7 +78,7 @@ run()
|
|||
.catch(err => console.error(err))
|
||||
|
||||
function run () {
|
||||
return new Promise(async res => {
|
||||
return new Promise<void>(async res => {
|
||||
const files = await getFiles()
|
||||
|
||||
for (const file of files) {
|
||||
|
@ -114,7 +116,7 @@ async function getNewestFile (files: string[], basePath: string) {
|
|||
}
|
||||
|
||||
async function getFiles () {
|
||||
if (program['files']) return program['files']
|
||||
if (options.files) return options.files
|
||||
|
||||
const logFiles = await readdir(CONFIG.STORAGE.LOG_DIR)
|
||||
|
||||
|
|
|
@ -12,12 +12,14 @@ program
|
|||
.option('-p, --plugin-path [pluginPath]', 'Path of the plugin you want to install')
|
||||
.parse(process.argv)
|
||||
|
||||
if (!program['npmName'] && !program['pluginPath']) {
|
||||
const options = program.opts()
|
||||
|
||||
if (!options.npmName && !options.pluginPath) {
|
||||
console.error('You need to specify a plugin name with the desired version, or a plugin path.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
if (program['pluginPath'] && !isAbsolute(program['pluginPath'])) {
|
||||
if (options.pluginPath && !isAbsolute(options.pluginPath)) {
|
||||
console.error('Plugin path should be absolute.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
@ -32,6 +34,6 @@ run()
|
|||
async function run () {
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const toInstall = program['npmName'] || program['pluginPath']
|
||||
await PluginManager.Instance.install(toInstall, program['pluginVersion'], !!program['pluginPath'])
|
||||
const toInstall = options.npmName || options.pluginPath
|
||||
await PluginManager.Instance.install(toInstall, options.pluginVersion, !!options.pluginPath)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,9 @@ program
|
|||
.option('-n, --npm-name [npmName]', 'Package name to install')
|
||||
.parse(process.argv)
|
||||
|
||||
if (!program['npmName']) {
|
||||
const options = program.opts()
|
||||
|
||||
if (!options.npmName) {
|
||||
console.error('You need to specify the plugin name.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
@ -25,6 +27,6 @@ async function run () {
|
|||
|
||||
await initDatabaseModels(true)
|
||||
|
||||
const toUninstall = program['npmName']
|
||||
const toUninstall = options.npmName
|
||||
await PluginManager.Instance.uninstall(toUninstall)
|
||||
}
|
||||
|
|
|
@ -10,14 +10,16 @@ program
|
|||
.option('-u, --user [user]', 'User')
|
||||
.parse(process.argv)
|
||||
|
||||
if (program['user'] === undefined) {
|
||||
const options = program.opts()
|
||||
|
||||
if (options.user === undefined) {
|
||||
console.error('All parameters are mandatory.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
initDatabaseModels(true)
|
||||
.then(() => {
|
||||
return UserModel.loadByUsername(program['user'])
|
||||
return UserModel.loadByUsername(options.user)
|
||||
})
|
||||
.then(user => {
|
||||
if (!user) {
|
||||
|
@ -28,7 +30,7 @@ initDatabaseModels(true)
|
|||
const readline = require('readline')
|
||||
const Writable = require('stream').Writable
|
||||
const mutableStdout = new Writable({
|
||||
write: function (chunk, encoding, callback) {
|
||||
write: function (_chunk, _encoding, callback) {
|
||||
callback()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -205,7 +205,8 @@ app.use('/', staticRouter)
|
|||
app.use('/', lazyStaticRouter)
|
||||
|
||||
// Client files, last valid routes!
|
||||
if (cli.client) app.use('/', clientsRouter)
|
||||
const cliOptions = cli.opts()
|
||||
if (cliOptions.client) app.use('/', clientsRouter)
|
||||
|
||||
// ----------- Errors -----------
|
||||
|
||||
|
@ -277,7 +278,7 @@ async function startApplication () {
|
|||
updateStreamingPlaylistsInfohashesIfNeeded()
|
||||
.catch(err => logger.error('Cannot update streaming playlist infohashes.', { err }))
|
||||
|
||||
if (cli.plugins) await PluginManager.Instance.registerPluginsAndThemes()
|
||||
if (cliOptions.plugins) await PluginManager.Instance.registerPluginsAndThemes()
|
||||
|
||||
LiveManager.Instance.init()
|
||||
if (CONFIG.LIVE.ENABLED) LiveManager.Instance.run()
|
||||
|
|
|
@ -30,7 +30,7 @@ export {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
function convertSrtToVtt (source: string, destination: string) {
|
||||
return new Promise((res, rej) => {
|
||||
return new Promise<void>((res, rej) => {
|
||||
const file = createReadStream(source)
|
||||
const converter = srt2vtt()
|
||||
const writer = createWriteStream(destination)
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
Useful to avoid circular dependencies.
|
||||
*/
|
||||
|
||||
import { createHash, HexBase64Latin1Encoding, randomBytes } from 'crypto'
|
||||
import { exec, ExecOptions } from 'child_process'
|
||||
import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto'
|
||||
import { truncate } from 'lodash'
|
||||
import { basename, isAbsolute, join, resolve } from 'path'
|
||||
import * as pem from 'pem'
|
||||
import { URL } from 'url'
|
||||
import { truncate } from 'lodash'
|
||||
import { exec, ExecOptions } from 'child_process'
|
||||
|
||||
const objectConverter = (oldObject: any, keyConverter: (e: string) => string, valueConverter: (e: any) => any) => {
|
||||
if (!oldObject || typeof oldObject !== 'object') {
|
||||
|
@ -205,11 +205,11 @@ function peertubeTruncate (str: string, options: { length: number, separator?: R
|
|||
return truncate(str, options)
|
||||
}
|
||||
|
||||
function sha256 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex') {
|
||||
function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') {
|
||||
return createHash('sha256').update(str).digest(encoding)
|
||||
}
|
||||
|
||||
function sha1 (str: string | Buffer, encoding: HexBase64Latin1Encoding = 'hex') {
|
||||
function sha1 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') {
|
||||
return createHash('sha1').update(str).digest(encoding)
|
||||
}
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ const lru = new AsyncLRU({
|
|||
}
|
||||
})
|
||||
|
||||
/* eslint-disable no-import-assign */
|
||||
jsonld.documentLoader = (url) => {
|
||||
return new Promise((res, rej) => {
|
||||
lru.get(url, (err, value) => {
|
||||
|
|
|
@ -61,7 +61,7 @@ const consoleLoggerFormat = winston.format.printf(info => {
|
|||
if (CONFIG.LOG.PRETTIFY_SQL) {
|
||||
additionalInfos += '\n' + sqlFormat(info.sql, {
|
||||
language: 'sql',
|
||||
ident: ' '
|
||||
indent: ' '
|
||||
})
|
||||
} else {
|
||||
additionalInfos += ' - ' + info.sql
|
||||
|
|
|
@ -149,7 +149,7 @@ function safeWebtorrentDestroy (
|
|||
downloadedFile?: { directoryPath: string, filepath: string },
|
||||
torrentName?: string
|
||||
) {
|
||||
return new Promise(res => {
|
||||
return new Promise<void>(res => {
|
||||
webtorrent.destroy(err => {
|
||||
// Delete torrent file
|
||||
if (torrentName) {
|
||||
|
|
|
@ -195,7 +195,7 @@ async function updateYoutubeDLBinary () {
|
|||
|
||||
await ensureDir(binDirectory)
|
||||
|
||||
return new Promise(res => {
|
||||
return new Promise<void>(res => {
|
||||
request.get(url, { followRedirect: false }, (err, result) => {
|
||||
if (err) {
|
||||
logger.error('Cannot update youtube-dl.', { err })
|
||||
|
|
|
@ -41,6 +41,7 @@ class InboxManager {
|
|||
|
||||
addInboxMessage (options: QueueParam) {
|
||||
this.inboxQueue.push(options)
|
||||
.catch(err => logger.error('Cannot add options in inbox queue.', { options, err }))
|
||||
}
|
||||
|
||||
static get Instance () {
|
||||
|
|
|
@ -65,7 +65,7 @@ const downloadImageQueue = queue<DownloadImageQueueTask, Error>((task, cb) => {
|
|||
}, QUEUE_CONCURRENCY.AVATAR_PROCESS_IMAGE)
|
||||
|
||||
function pushAvatarProcessInQueue (task: DownloadImageQueueTask) {
|
||||
return new Promise((res, rej) => {
|
||||
return new Promise<void>((res, rej) => {
|
||||
downloadImageQueue.push(task, err => {
|
||||
if (err) return rej(err)
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ function downloadPlaylistSegments (playlistUrl: string, destinationDir: string,
|
|||
|
||||
logger.info('Importing HLS playlist %s', playlistUrl)
|
||||
|
||||
return new Promise<string>(async (res, rej) => {
|
||||
return new Promise<void>(async (res, rej) => {
|
||||
const tmpDirectory = join(CONFIG.STORAGE.TMP_DIR, await generateRandomString(10))
|
||||
|
||||
await ensureDir(tmpDirectory)
|
||||
|
|
|
@ -263,7 +263,7 @@ class Redis {
|
|||
}
|
||||
|
||||
private addToSet (key: string, value: string) {
|
||||
return new Promise<string[]>((res, rej) => {
|
||||
return new Promise<void>((res, rej) => {
|
||||
this.client.sadd(this.prefix + key, value, err => err ? rej(err) : res())
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import { eachSeries } from 'async'
|
||||
import { NextFunction, Request, RequestHandler, Response } from 'express'
|
||||
import { retryTransactionWrapper } from '../helpers/database-utils'
|
||||
import { ValidationChain } from 'express-validator'
|
||||
import { ExpressPromiseHandler } from '@server/types/express'
|
||||
import { retryTransactionWrapper } from '../helpers/database-utils'
|
||||
|
||||
// Syntactic sugar to avoid try/catch in express controllers
|
||||
// Thanks: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
|
||||
|
||||
export type RequestPromiseHandler = ValidationChain | ((req: Request, res: Response, next: NextFunction) => Promise<any>)
|
||||
export type RequestPromiseHandler = ValidationChain | ExpressPromiseHandler
|
||||
|
||||
function asyncMiddleware (fun: RequestPromiseHandler | RequestPromiseHandler[]) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
|
|
|
@ -49,7 +49,7 @@ function authenticateSocket (socket: Socket, next: (err?: any) => void) {
|
|||
}
|
||||
|
||||
function authenticatePromiseIfNeeded (req: express.Request, res: express.Response, authenticateInQuery = false) {
|
||||
return new Promise(resolve => {
|
||||
return new Promise<void>(resolve => {
|
||||
// Already authenticated? (or tried to)
|
||||
if (res.locals.oauth?.token.User) return resolve()
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-code
|
|||
const startVideoPlaylistsURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch', 'playlist') + '/'
|
||||
const startVideosURL = WEBSERVER.SCHEME + '://' + join(WEBSERVER.HOST, 'videos', 'watch') + '/'
|
||||
|
||||
const watchRegex = new RegExp('([^/]+)$')
|
||||
const watchRegex = /([^/]+)$/
|
||||
const isURLOptions = {
|
||||
require_host: true,
|
||||
require_tld: true
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import * as express from 'express'
|
||||
import { body, param, query, ValidationChain } from 'express-validator'
|
||||
import { ExpressPromiseHandler } from '@server/types/express'
|
||||
import { MUserAccountId } from '@server/types/models'
|
||||
import { UserRight, VideoPlaylistCreate, VideoPlaylistUpdate } from '../../../../shared'
|
||||
import { logger } from '../../../helpers/logger'
|
||||
import { areValidationErrors } from '../utils'
|
||||
import { isVideoImage } from '../../../helpers/custom-validators/videos'
|
||||
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
|
||||
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
|
||||
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
|
||||
import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
|
||||
import {
|
||||
isArrayOf,
|
||||
isIdOrUUIDValid,
|
||||
|
@ -21,15 +22,15 @@ import {
|
|||
isVideoPlaylistTimestampValid,
|
||||
isVideoPlaylistTypeValid
|
||||
} from '../../../helpers/custom-validators/video-playlists'
|
||||
import { isVideoImage } from '../../../helpers/custom-validators/videos'
|
||||
import { cleanUpReqFiles } from '../../../helpers/express-utils'
|
||||
import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element'
|
||||
import { authenticatePromiseIfNeeded } from '../../oauth'
|
||||
import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
|
||||
import { VideoPlaylistType } from '../../../../shared/models/videos/playlist/video-playlist-type.model'
|
||||
import { logger } from '../../../helpers/logger'
|
||||
import { doesVideoChannelIdExist, doesVideoExist, doesVideoPlaylistExist, VideoPlaylistFetchType } from '../../../helpers/middlewares'
|
||||
import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
|
||||
import { VideoPlaylistElementModel } from '../../../models/video/video-playlist-element'
|
||||
import { MVideoPlaylist } from '../../../types/models/video/video-playlist'
|
||||
import { MUserAccountId } from '@server/types/models'
|
||||
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
|
||||
import { authenticatePromiseIfNeeded } from '../../oauth'
|
||||
import { areValidationErrors } from '../utils'
|
||||
|
||||
const videoPlaylistsAddValidator = getCommonPlaylistEditAttributes().concat([
|
||||
body('displayName')
|
||||
|
@ -395,7 +396,7 @@ function getCommonPlaylistEditAttributes () {
|
|||
body('videoChannelId')
|
||||
.optional()
|
||||
.customSanitizer(toIntOrNull)
|
||||
] as (ValidationChain | express.Handler)[]
|
||||
] as (ValidationChain | ExpressPromiseHandler)[]
|
||||
}
|
||||
|
||||
function checkUserCanManageVideoPlaylist (user: MUserAccountId, videoPlaylist: MVideoPlaylist, right: UserRight, res: express.Response) {
|
||||
|
|
|
@ -2,8 +2,10 @@ import * as express from 'express'
|
|||
import { body, param, query, ValidationChain } from 'express-validator'
|
||||
import { isAbleToUploadVideo } from '@server/lib/user'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import { ExpressPromiseHandler } from '@server/types/express'
|
||||
import { MVideoFullLight } from '@server/types/models'
|
||||
import { ServerErrorCode, UserRight, VideoChangeOwnershipStatus, VideoPrivacy } from '../../../../shared'
|
||||
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
|
||||
import { VideoChangeOwnershipAccept } from '../../../../shared/models/videos/video-change-ownership-accept.model'
|
||||
import {
|
||||
exists,
|
||||
|
@ -54,7 +56,6 @@ import { AccountModel } from '../../../models/account/account'
|
|||
import { VideoModel } from '../../../models/video/video'
|
||||
import { authenticatePromiseIfNeeded } from '../../oauth'
|
||||
import { areValidationErrors } from '../utils'
|
||||
import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes'
|
||||
|
||||
const videosAddValidator = getCommonVideoEditAttributes().concat([
|
||||
body('videofile')
|
||||
|
@ -411,7 +412,7 @@ function getCommonVideoEditAttributes () {
|
|||
.optional()
|
||||
.customSanitizer(toIntOrNull)
|
||||
.custom(isScheduleVideoUpdatePrivacyValid).withMessage('Should have correct schedule update privacy')
|
||||
] as (ValidationChain | express.Handler)[]
|
||||
] as (ValidationChain | ExpressPromiseHandler)[]
|
||||
}
|
||||
|
||||
const commonVideosFiltersValidator = [
|
||||
|
|
|
@ -469,27 +469,33 @@ export class UserNotificationModel extends Model {
|
|||
? Object.assign(this.formatVideo(this.Video), { channel: this.formatActor(this.Video.VideoChannel) })
|
||||
: undefined
|
||||
|
||||
const videoImport = this.VideoImport ? {
|
||||
id: this.VideoImport.id,
|
||||
video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined,
|
||||
torrentName: this.VideoImport.torrentName,
|
||||
magnetUri: this.VideoImport.magnetUri,
|
||||
targetUrl: this.VideoImport.targetUrl
|
||||
} : undefined
|
||||
const videoImport = this.VideoImport
|
||||
? {
|
||||
id: this.VideoImport.id,
|
||||
video: this.VideoImport.Video ? this.formatVideo(this.VideoImport.Video) : undefined,
|
||||
torrentName: this.VideoImport.torrentName,
|
||||
magnetUri: this.VideoImport.magnetUri,
|
||||
targetUrl: this.VideoImport.targetUrl
|
||||
}
|
||||
: undefined
|
||||
|
||||
const comment = this.Comment ? {
|
||||
id: this.Comment.id,
|
||||
threadId: this.Comment.getThreadId(),
|
||||
account: this.formatActor(this.Comment.Account),
|
||||
video: this.formatVideo(this.Comment.Video)
|
||||
} : undefined
|
||||
const comment = this.Comment
|
||||
? {
|
||||
id: this.Comment.id,
|
||||
threadId: this.Comment.getThreadId(),
|
||||
account: this.formatActor(this.Comment.Account),
|
||||
video: this.formatVideo(this.Comment.Video)
|
||||
}
|
||||
: undefined
|
||||
|
||||
const abuse = this.Abuse ? this.formatAbuse(this.Abuse) : undefined
|
||||
|
||||
const videoBlacklist = this.VideoBlacklist ? {
|
||||
id: this.VideoBlacklist.id,
|
||||
video: this.formatVideo(this.VideoBlacklist.Video)
|
||||
} : undefined
|
||||
const videoBlacklist = this.VideoBlacklist
|
||||
? {
|
||||
id: this.VideoBlacklist.id,
|
||||
video: this.formatVideo(this.VideoBlacklist.Video)
|
||||
}
|
||||
: undefined
|
||||
|
||||
const account = this.Account ? this.formatActor(this.Account) : undefined
|
||||
|
||||
|
@ -498,23 +504,25 @@ export class UserNotificationModel extends Model {
|
|||
Group: 'channel' as 'channel',
|
||||
Person: 'account' as 'account'
|
||||
}
|
||||
const actorFollow = this.ActorFollow ? {
|
||||
id: this.ActorFollow.id,
|
||||
state: this.ActorFollow.state,
|
||||
follower: {
|
||||
id: this.ActorFollow.ActorFollower.Account.id,
|
||||
displayName: this.ActorFollow.ActorFollower.Account.getDisplayName(),
|
||||
name: this.ActorFollow.ActorFollower.preferredUsername,
|
||||
avatar: this.ActorFollow.ActorFollower.Avatar ? { path: this.ActorFollow.ActorFollower.Avatar.getStaticPath() } : undefined,
|
||||
host: this.ActorFollow.ActorFollower.getHost()
|
||||
},
|
||||
following: {
|
||||
type: actorFollowingType[this.ActorFollow.ActorFollowing.type],
|
||||
displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(),
|
||||
name: this.ActorFollow.ActorFollowing.preferredUsername,
|
||||
host: this.ActorFollow.ActorFollowing.getHost()
|
||||
const actorFollow = this.ActorFollow
|
||||
? {
|
||||
id: this.ActorFollow.id,
|
||||
state: this.ActorFollow.state,
|
||||
follower: {
|
||||
id: this.ActorFollow.ActorFollower.Account.id,
|
||||
displayName: this.ActorFollow.ActorFollower.Account.getDisplayName(),
|
||||
name: this.ActorFollow.ActorFollower.preferredUsername,
|
||||
avatar: this.ActorFollow.ActorFollower.Avatar ? { path: this.ActorFollow.ActorFollower.Avatar.getStaticPath() } : undefined,
|
||||
host: this.ActorFollow.ActorFollower.getHost()
|
||||
},
|
||||
following: {
|
||||
type: actorFollowingType[this.ActorFollow.ActorFollowing.type],
|
||||
displayName: (this.ActorFollow.ActorFollowing.VideoChannel || this.ActorFollow.ActorFollowing.Account).getDisplayName(),
|
||||
name: this.ActorFollow.ActorFollowing.preferredUsername,
|
||||
host: this.ActorFollow.ActorFollowing.getHost()
|
||||
}
|
||||
}
|
||||
} : undefined
|
||||
: undefined
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
|
@ -541,15 +549,17 @@ export class UserNotificationModel extends Model {
|
|||
}
|
||||
|
||||
formatAbuse (this: UserNotificationModelForApi, abuse: UserNotificationIncludes.AbuseInclude) {
|
||||
const commentAbuse = abuse.VideoCommentAbuse?.VideoComment ? {
|
||||
threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(),
|
||||
const commentAbuse = abuse.VideoCommentAbuse?.VideoComment
|
||||
? {
|
||||
threadId: abuse.VideoCommentAbuse.VideoComment.getThreadId(),
|
||||
|
||||
video: {
|
||||
id: abuse.VideoCommentAbuse.VideoComment.Video.id,
|
||||
name: abuse.VideoCommentAbuse.VideoComment.Video.name,
|
||||
uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid
|
||||
video: {
|
||||
id: abuse.VideoCommentAbuse.VideoComment.Video.id,
|
||||
name: abuse.VideoCommentAbuse.VideoComment.Video.name,
|
||||
uuid: abuse.VideoCommentAbuse.VideoComment.Video.uuid
|
||||
}
|
||||
}
|
||||
} : undefined
|
||||
: undefined
|
||||
|
||||
const videoAbuse = abuse.VideoAbuse?.Video ? this.formatVideo(abuse.VideoAbuse.Video) : undefined
|
||||
|
||||
|
|
|
@ -82,9 +82,9 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFor
|
|||
account: video.VideoChannel.Account.toFormattedSummaryJSON(),
|
||||
channel: video.VideoChannel.toFormattedSummaryJSON(),
|
||||
|
||||
userHistory: userHistory ? {
|
||||
currentTime: userHistory.currentTime
|
||||
} : undefined,
|
||||
userHistory: userHistory
|
||||
? { currentTime: userHistory.currentTime }
|
||||
: undefined,
|
||||
|
||||
// Can be added by external plugins
|
||||
pluginData: (video as any).pluginData
|
||||
|
|
|
@ -69,23 +69,25 @@ function deleteSettings () {
|
|||
}
|
||||
|
||||
function getRemoteObjectOrDie (
|
||||
program: any,
|
||||
program: CommanderStatic,
|
||||
settings: Settings,
|
||||
netrc: Netrc
|
||||
): { url: string, username: string, password: string } {
|
||||
if (!program['url'] || !program['username'] || !program['password']) {
|
||||
const options = program.opts()
|
||||
|
||||
if (!options.url || !options.username || !options.password) {
|
||||
// No remote and we don't have program parameters: quit
|
||||
if (settings.remotes.length === 0 || Object.keys(netrc.machines).length === 0) {
|
||||
if (!program['url']) console.error('--url field is required.')
|
||||
if (!program['username']) console.error('--username field is required.')
|
||||
if (!program['password']) console.error('--password field is required.')
|
||||
if (!options.url) console.error('--url field is required.')
|
||||
if (!options.username) console.error('--username field is required.')
|
||||
if (!options.password) console.error('--password field is required.')
|
||||
|
||||
return process.exit(-1)
|
||||
}
|
||||
|
||||
let url: string = program['url']
|
||||
let username: string = program['username']
|
||||
let password: string = program['password']
|
||||
let url: string = options.url
|
||||
let username: string = options.username
|
||||
let password: string = options.password
|
||||
|
||||
if (!url && settings.default !== -1) url = settings.remotes[settings.default]
|
||||
|
||||
|
@ -98,9 +100,9 @@ function getRemoteObjectOrDie (
|
|||
}
|
||||
|
||||
return {
|
||||
url: program['url'],
|
||||
username: program['username'],
|
||||
password: program['password']
|
||||
url: options.url,
|
||||
username: options.username,
|
||||
password: options.password
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,6 +129,8 @@ function buildCommonVideoOptions (command: CommanderStatic) {
|
|||
}
|
||||
|
||||
async function buildVideoAttributesFromCommander (url: string, command: CommanderStatic, defaultAttributes: any = {}) {
|
||||
const options = command.opts()
|
||||
|
||||
const defaultBooleanAttributes = {
|
||||
nsfw: false,
|
||||
commentsEnabled: true,
|
||||
|
@ -137,8 +141,8 @@ async function buildVideoAttributesFromCommander (url: string, command: Commande
|
|||
const booleanAttributes: { [id in keyof typeof defaultBooleanAttributes]: boolean } | {} = {}
|
||||
|
||||
for (const key of Object.keys(defaultBooleanAttributes)) {
|
||||
if (command[key] !== undefined) {
|
||||
booleanAttributes[key] = command[key]
|
||||
if (options[key] !== undefined) {
|
||||
booleanAttributes[key] = options[key]
|
||||
} else if (defaultAttributes[key] !== undefined) {
|
||||
booleanAttributes[key] = defaultAttributes[key]
|
||||
} else {
|
||||
|
@ -147,20 +151,20 @@ async function buildVideoAttributesFromCommander (url: string, command: Commande
|
|||
}
|
||||
|
||||
const videoAttributes = {
|
||||
name: command['videoName'] || defaultAttributes.name,
|
||||
category: command['category'] || defaultAttributes.category || undefined,
|
||||
licence: command['licence'] || defaultAttributes.licence || undefined,
|
||||
language: command['language'] || defaultAttributes.language || undefined,
|
||||
privacy: command['privacy'] || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
|
||||
support: command['support'] || defaultAttributes.support || undefined,
|
||||
description: command['videoDescription'] || defaultAttributes.description || undefined,
|
||||
tags: command['tags'] || defaultAttributes.tags || undefined
|
||||
name: options.videoName || defaultAttributes.name,
|
||||
category: options.category || defaultAttributes.category || undefined,
|
||||
licence: options.licence || defaultAttributes.licence || undefined,
|
||||
language: options.language || defaultAttributes.language || undefined,
|
||||
privacy: options.privacy || defaultAttributes.privacy || VideoPrivacy.PUBLIC,
|
||||
support: options.support || defaultAttributes.support || undefined,
|
||||
description: options.videoDescription || defaultAttributes.description || undefined,
|
||||
tags: options.tags || defaultAttributes.tags || undefined
|
||||
}
|
||||
|
||||
Object.assign(videoAttributes, booleanAttributes)
|
||||
|
||||
if (command['channelName']) {
|
||||
const res = await getVideoChannel(url, command['channelName'])
|
||||
if (options.channelName) {
|
||||
const res = await getVideoChannel(url, options.channelName)
|
||||
const videoChannel: VideoChannel = res.body
|
||||
|
||||
Object.assign(videoAttributes, { channelId: videoChannel.id })
|
||||
|
@ -173,7 +177,7 @@ async function buildVideoAttributesFromCommander (url: string, command: Commande
|
|||
return videoAttributes
|
||||
}
|
||||
|
||||
function getServerCredentials (program: any) {
|
||||
function getServerCredentials (program: CommanderStatic) {
|
||||
return Promise.all([ getSettings(), getNetrc() ])
|
||||
.then(([ settings, netrc ]) => {
|
||||
return getRemoteObjectOrDie(program, settings, netrc)
|
||||
|
|
|
@ -66,7 +66,8 @@ program
|
|||
.option('-U, --username <username>', 'Username')
|
||||
.option('-p, --password <token>', 'Password')
|
||||
.option('--default', 'add the entry as the new default')
|
||||
.action(options => {
|
||||
.action((options: program.OptionValues) => {
|
||||
/* eslint-disable no-import-assign */
|
||||
prompt.override = options
|
||||
prompt.start()
|
||||
prompt.get({
|
||||
|
@ -102,7 +103,7 @@ program
|
|||
process.exit(-1)
|
||||
}
|
||||
|
||||
await setInstance(result.url, result.username, result.password, program['default'])
|
||||
await setInstance(result.url, result.username, result.password, options.default)
|
||||
|
||||
process.exit(0)
|
||||
})
|
||||
|
@ -160,15 +161,12 @@ program
|
|||
}
|
||||
})
|
||||
|
||||
program.on('--help', function () {
|
||||
console.log(' Examples:')
|
||||
console.log()
|
||||
console.log(' $ peertube auth add -u https://peertube.cpy.re -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"')
|
||||
console.log(' $ peertube auth add -u https://peertube.cpy.re -U root')
|
||||
console.log(' $ peertube auth list')
|
||||
console.log(' $ peertube auth del https://peertube.cpy.re')
|
||||
console.log()
|
||||
})
|
||||
program.addHelpText('after', '\n\n Examples:\n\n' +
|
||||
' $ peertube auth add -u https://peertube.cpy.re -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"\n' +
|
||||
' $ peertube auth add -u https://peertube.cpy.re -U root\n' +
|
||||
' $ peertube auth list\n' +
|
||||
' $ peertube auth del https://peertube.cpy.re\n'
|
||||
)
|
||||
|
||||
if (!process.argv.slice(2).length) {
|
||||
program.outputHelp()
|
||||
|
|
|
@ -10,25 +10,27 @@ program
|
|||
.option('-p, --password <token>', 'Password')
|
||||
.parse(process.argv)
|
||||
|
||||
const options = program.opts()
|
||||
|
||||
if (
|
||||
!program['url'] ||
|
||||
!program['username'] ||
|
||||
!program['password']
|
||||
!options.url ||
|
||||
!options.username ||
|
||||
!options.password
|
||||
) {
|
||||
if (!program['url']) console.error('--url field is required.')
|
||||
if (!program['username']) console.error('--username field is required.')
|
||||
if (!program['password']) console.error('--password field is required.')
|
||||
if (!options.url) console.error('--url field is required.')
|
||||
if (!options.username) console.error('--username field is required.')
|
||||
if (!options.password) console.error('--password field is required.')
|
||||
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
getClient(program.url)
|
||||
getClient(options.url)
|
||||
.then(res => {
|
||||
const server = {
|
||||
url: program['url'],
|
||||
url: options.url,
|
||||
user: {
|
||||
username: program['username'],
|
||||
password: program['password']
|
||||
username: options.username,
|
||||
password: options.password
|
||||
},
|
||||
client: {
|
||||
id: res.body.client_id,
|
||||
|
|
|
@ -45,22 +45,24 @@ command
|
|||
.usage("[global options] [ -- youtube-dl options]")
|
||||
.parse(process.argv)
|
||||
|
||||
const log = getLogger(program['verbose'])
|
||||
const options = command.opts()
|
||||
|
||||
const log = getLogger(options.verbose)
|
||||
|
||||
getServerCredentials(command)
|
||||
.then(({ url, username, password }) => {
|
||||
if (!program['targetUrl']) {
|
||||
if (!options.targetUrl) {
|
||||
exitError('--target-url field is required.')
|
||||
}
|
||||
|
||||
try {
|
||||
accessSync(program['tmpdir'], constants.R_OK | constants.W_OK)
|
||||
accessSync(options.tmpdir, constants.R_OK | constants.W_OK)
|
||||
} catch (e) {
|
||||
exitError('--tmpdir %s: directory does not exist or is not accessible', program['tmpdir'])
|
||||
exitError('--tmpdir %s: directory does not exist or is not accessible', options.tmpdir)
|
||||
}
|
||||
|
||||
url = normalizeTargetUrl(url)
|
||||
program['targetUrl'] = normalizeTargetUrl(program['targetUrl'])
|
||||
options.targetUrl = normalizeTargetUrl(options.targetUrl)
|
||||
|
||||
const user = { username, password }
|
||||
|
||||
|
@ -76,7 +78,7 @@ async function run (url: string, user: UserInfo) {
|
|||
|
||||
const youtubeDL = await safeGetYoutubeDL()
|
||||
|
||||
let info = await getYoutubeDLInfo(youtubeDL, program['targetUrl'], command.args)
|
||||
let info = await getYoutubeDLInfo(youtubeDL, options.targetUrl, command.args)
|
||||
|
||||
if (!Array.isArray(info)) info = [ info ]
|
||||
|
||||
|
@ -92,10 +94,10 @@ async function run (url: string, user: UserInfo) {
|
|||
let infoArray: any[]
|
||||
|
||||
infoArray = [].concat(info)
|
||||
if (program['first']) {
|
||||
infoArray = infoArray.slice(0, program['first'])
|
||||
} else if (program['last']) {
|
||||
infoArray = infoArray.slice(-program['last'])
|
||||
if (options.first) {
|
||||
infoArray = infoArray.slice(0, options.first)
|
||||
} else if (options.last) {
|
||||
infoArray = infoArray.slice(-options.last)
|
||||
}
|
||||
// Normalize utf8 fields
|
||||
infoArray = infoArray.map(i => normalizeObject(i))
|
||||
|
@ -104,12 +106,12 @@ async function run (url: string, user: UserInfo) {
|
|||
|
||||
for (const [ index, info ] of infoArray.entries()) {
|
||||
try {
|
||||
if (index > 0 && program['waitInterval']) {
|
||||
log.info("Wait for %d seconds before continuing.", program['waitInterval'] / 1000)
|
||||
await new Promise(res => setTimeout(res, program['waitInterval']))
|
||||
if (index > 0 && options.waitInterval) {
|
||||
log.info("Wait for %d seconds before continuing.", options.waitInterval / 1000)
|
||||
await new Promise(res => setTimeout(res, options.waitInterval))
|
||||
}
|
||||
await processVideo({
|
||||
cwd: program['tmpdir'],
|
||||
cwd: options.tmpdir,
|
||||
url,
|
||||
user,
|
||||
youtubeInfo: info
|
||||
|
@ -119,7 +121,7 @@ async function run (url: string, user: UserInfo) {
|
|||
}
|
||||
}
|
||||
|
||||
log.info('Video/s for user %s imported: %s', user.username, program['targetUrl'])
|
||||
log.info('Video/s for user %s imported: %s', user.username, options.targetUrl)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
|
@ -137,14 +139,14 @@ async function processVideo (parameters: {
|
|||
log.debug('Fetched object.', videoInfo)
|
||||
|
||||
const originallyPublishedAt = buildOriginallyPublishedAt(videoInfo)
|
||||
if (program['since'] && originallyPublishedAt && originallyPublishedAt.getTime() < program['since'].getTime()) {
|
||||
if (options.since && originallyPublishedAt && originallyPublishedAt.getTime() < options.since.getTime()) {
|
||||
log.info('Video "%s" has been published before "%s", don\'t upload it.\n',
|
||||
videoInfo.title, formatDate(program['since']))
|
||||
videoInfo.title, formatDate(options.since))
|
||||
return
|
||||
}
|
||||
if (program['until'] && originallyPublishedAt && originallyPublishedAt.getTime() > program['until'].getTime()) {
|
||||
if (options.until && originallyPublishedAt && originallyPublishedAt.getTime() > options.until.getTime()) {
|
||||
log.info('Video "%s" has been published after "%s", don\'t upload it.\n',
|
||||
videoInfo.title, formatDate(program['until']))
|
||||
videoInfo.title, formatDate(options.until))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -161,11 +163,11 @@ async function processVideo (parameters: {
|
|||
|
||||
log.info('Downloading video "%s"...', videoInfo.title)
|
||||
|
||||
const options = [ '-f', getYoutubeDLVideoFormat(), ...command.args, '-o', path ]
|
||||
const youtubeDLOptions = [ '-f', getYoutubeDLVideoFormat(), ...command.args, '-o', path ]
|
||||
try {
|
||||
const youtubeDL = await safeGetYoutubeDL()
|
||||
const youtubeDLExec = promisify(youtubeDL.exec).bind(youtubeDL)
|
||||
const output = await youtubeDLExec(videoInfo.url, options, processOptions)
|
||||
const output = await youtubeDLExec(videoInfo.url, youtubeDLOptions, processOptions)
|
||||
log.info(output.join('\n'))
|
||||
await uploadVideoOnPeerTube({
|
||||
cwd,
|
||||
|
|
|
@ -10,6 +10,7 @@ import { getAdminTokenOrDie, getServerCredentials } from './cli'
|
|||
import { PeerTubePlugin } from '../../shared/models/plugins/peertube-plugin.model'
|
||||
import { isAbsolute } from 'path'
|
||||
import * as CliTable3 from 'cli-table3'
|
||||
import commander = require('commander')
|
||||
|
||||
program
|
||||
.name('plugins')
|
||||
|
@ -33,7 +34,7 @@ program
|
|||
.option('-p, --password <token>', 'Password')
|
||||
.option('-P --path <path>', 'Install from a path')
|
||||
.option('-n, --npm-name <npmName>', 'Install from npm')
|
||||
.action((options) => installPluginCLI(options))
|
||||
.action((options, command) => installPluginCLI(command, options))
|
||||
|
||||
program
|
||||
.command('update')
|
||||
|
@ -43,7 +44,7 @@ program
|
|||
.option('-p, --password <token>', 'Password')
|
||||
.option('-P --path <path>', 'Update from a path')
|
||||
.option('-n, --npm-name <npmName>', 'Update from npm')
|
||||
.action((options) => updatePluginCLI(options))
|
||||
.action((options, command) => updatePluginCLI(command, options))
|
||||
|
||||
program
|
||||
.command('uninstall')
|
||||
|
@ -52,7 +53,7 @@ program
|
|||
.option('-U, --username <username>', 'Username')
|
||||
.option('-p, --password <token>', 'Password')
|
||||
.option('-n, --npm-name <npmName>', 'NPM plugin/theme name')
|
||||
.action(options => uninstallPluginCLI(options))
|
||||
.action((options, command) => uninstallPluginCLI(command, options))
|
||||
|
||||
if (!process.argv.slice(2).length) {
|
||||
program.outputHelp()
|
||||
|
@ -60,6 +61,8 @@ if (!process.argv.slice(2).length) {
|
|||
|
||||
program.parse(process.argv)
|
||||
|
||||
const options = program.opts()
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
async function pluginsListCLI () {
|
||||
|
@ -67,8 +70,8 @@ async function pluginsListCLI () {
|
|||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
let pluginType: PluginType
|
||||
if (program['onlyThemes']) pluginType = PluginType.THEME
|
||||
if (program['onlyPlugins']) pluginType = PluginType.PLUGIN
|
||||
if (options.onlyThemes) pluginType = PluginType.THEME
|
||||
if (options.onlyPlugins) pluginType = PluginType.PLUGIN
|
||||
|
||||
const res = await listPlugins({
|
||||
url,
|
||||
|
@ -101,27 +104,27 @@ async function pluginsListCLI () {
|
|||
process.exit(0)
|
||||
}
|
||||
|
||||
async function installPluginCLI (options: any) {
|
||||
if (!options['path'] && !options['npmName']) {
|
||||
async function installPluginCLI (command: commander.CommanderStatic, options: commander.OptionValues) {
|
||||
if (!options.path && !options.npmName) {
|
||||
console.error('You need to specify the npm name or the path of the plugin you want to install.\n')
|
||||
program.outputHelp()
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
if (options['path'] && !isAbsolute(options['path'])) {
|
||||
if (options.path && !isAbsolute(options.path)) {
|
||||
console.error('Path should be absolute.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
const { url, username, password } = await getServerCredentials(options)
|
||||
const { url, username, password } = await getServerCredentials(command)
|
||||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
try {
|
||||
await installPlugin({
|
||||
url,
|
||||
accessToken,
|
||||
npmName: options['npmName'],
|
||||
path: options['path']
|
||||
npmName: options.npmName,
|
||||
path: options.path
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot install plugin.', err)
|
||||
|
@ -132,27 +135,27 @@ async function installPluginCLI (options: any) {
|
|||
process.exit(0)
|
||||
}
|
||||
|
||||
async function updatePluginCLI (options: any) {
|
||||
if (!options['path'] && !options['npmName']) {
|
||||
async function updatePluginCLI (command: commander.CommanderStatic, options: commander.OptionValues) {
|
||||
if (!options.path && !options.npmName) {
|
||||
console.error('You need to specify the npm name or the path of the plugin you want to update.\n')
|
||||
program.outputHelp()
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
if (options['path'] && !isAbsolute(options['path'])) {
|
||||
if (options.path && !isAbsolute(options.path)) {
|
||||
console.error('Path should be absolute.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
const { url, username, password } = await getServerCredentials(options)
|
||||
const { url, username, password } = await getServerCredentials(command)
|
||||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
try {
|
||||
await updatePlugin({
|
||||
url,
|
||||
accessToken,
|
||||
npmName: options['npmName'],
|
||||
path: options['path']
|
||||
npmName: options.npmName,
|
||||
path: options.path
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot update plugin.', err)
|
||||
|
@ -163,21 +166,21 @@ async function updatePluginCLI (options: any) {
|
|||
process.exit(0)
|
||||
}
|
||||
|
||||
async function uninstallPluginCLI (options: any) {
|
||||
if (!options['npmName']) {
|
||||
async function uninstallPluginCLI (command: commander.CommanderStatic, options: commander.OptionValues) {
|
||||
if (!options.npmName) {
|
||||
console.error('You need to specify the npm name of the plugin/theme you want to uninstall.\n')
|
||||
program.outputHelp()
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
const { url, username, password } = await getServerCredentials(options)
|
||||
const { url, username, password } = await getServerCredentials(command)
|
||||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
try {
|
||||
await uninstallPlugin({
|
||||
url,
|
||||
accessToken,
|
||||
npmName: options['npmName']
|
||||
npmName: options.npmName
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('Cannot uninstall plugin.', err)
|
||||
|
|
|
@ -14,6 +14,7 @@ import { URL } from 'url'
|
|||
import { uniq } from 'lodash'
|
||||
|
||||
import bytes = require('bytes')
|
||||
import commander = require('commander')
|
||||
|
||||
program
|
||||
.name('plugins')
|
||||
|
@ -42,7 +43,7 @@ program
|
|||
.option('-U, --username <username>', 'Username')
|
||||
.option('-p, --password <token>', 'Password')
|
||||
.option('-v, --video <videoId>', 'Video id to duplicate')
|
||||
.action((options) => addRedundancyCLI(options))
|
||||
.action((options, command) => addRedundancyCLI(options, command))
|
||||
|
||||
program
|
||||
.command('remove')
|
||||
|
@ -51,7 +52,7 @@ program
|
|||
.option('-U, --username <username>', 'Username')
|
||||
.option('-p, --password <token>', 'Password')
|
||||
.option('-v, --video <videoId>', 'Video id to remove from redundancies')
|
||||
.action((options) => removeRedundancyCLI(options))
|
||||
.action((options, command) => removeRedundancyCLI(options, command))
|
||||
|
||||
if (!process.argv.slice(2).length) {
|
||||
program.outputHelp()
|
||||
|
@ -104,13 +105,13 @@ async function listRedundanciesCLI (target: VideoRedundanciesTarget) {
|
|||
process.exit(0)
|
||||
}
|
||||
|
||||
async function addRedundancyCLI (options: { videoId: number }) {
|
||||
const { url, username, password } = await getServerCredentials(program)
|
||||
async function addRedundancyCLI (options: { video: number }, command: commander.CommanderStatic) {
|
||||
const { url, username, password } = await getServerCredentials(command)
|
||||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
if (!options['video'] || validator.isInt('' + options['video']) === false) {
|
||||
if (!options.video || validator.isInt('' + options.video) === false) {
|
||||
console.error('You need to specify the video id to duplicate and it should be a number.\n')
|
||||
program.outputHelp()
|
||||
command.outputHelp()
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
|
@ -118,7 +119,7 @@ async function addRedundancyCLI (options: { videoId: number }) {
|
|||
await addVideoRedundancy({
|
||||
url,
|
||||
accessToken,
|
||||
videoId: options['video']
|
||||
videoId: options.video
|
||||
})
|
||||
|
||||
console.log('Video will be duplicated by your instance!')
|
||||
|
@ -137,17 +138,17 @@ async function addRedundancyCLI (options: { videoId: number }) {
|
|||
}
|
||||
}
|
||||
|
||||
async function removeRedundancyCLI (options: { videoId: number }) {
|
||||
const { url, username, password } = await getServerCredentials(program)
|
||||
async function removeRedundancyCLI (options: { video: number }, command: commander.CommanderStatic) {
|
||||
const { url, username, password } = await getServerCredentials(command)
|
||||
const accessToken = await getAdminTokenOrDie(url, username, password)
|
||||
|
||||
if (!options['video'] || validator.isInt('' + options['video']) === false) {
|
||||
if (!options.video || validator.isInt('' + options.video) === false) {
|
||||
console.error('You need to specify the video id to remove from your redundancies.\n')
|
||||
program.outputHelp()
|
||||
command.outputHelp()
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
const videoId = parseInt(options['video'] + '', 10)
|
||||
const videoId = parseInt(options.video + '', 10)
|
||||
|
||||
let redundancies = await listVideoRedundanciesData(url, accessToken, 'my-videos')
|
||||
let videoRedundancy = redundancies.find(r => videoId === r.id)
|
||||
|
|
|
@ -82,7 +82,6 @@ const start = async () => {
|
|||
}
|
||||
replServer.defineCommand('reset', resetCommand)
|
||||
replServer.defineCommand('r', resetCommand)
|
||||
|
||||
}
|
||||
|
||||
start()
|
||||
|
|
|
@ -22,16 +22,18 @@ command
|
|||
.option('-f, --file <file>', 'Video absolute file path')
|
||||
.parse(process.argv)
|
||||
|
||||
const options = command.opts()
|
||||
|
||||
getServerCredentials(command)
|
||||
.then(({ url, username, password }) => {
|
||||
if (!program['videoName'] || !program['file']) {
|
||||
if (!program['videoName']) console.error('--video-name is required.')
|
||||
if (!program['file']) console.error('--file is required.')
|
||||
if (!options.videoName || !options.file) {
|
||||
if (!options.videoName) console.error('--video-name is required.')
|
||||
if (!options.file) console.error('--file is required.')
|
||||
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
if (isAbsolute(program['file']) === false) {
|
||||
if (isAbsolute(options.file) === false) {
|
||||
console.error('File path should be absolute.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
@ -46,21 +48,21 @@ getServerCredentials(command)
|
|||
async function run (url: string, username: string, password: string) {
|
||||
const accessToken = await getAccessToken(url, username, password)
|
||||
|
||||
await access(program['file'], constants.F_OK)
|
||||
await access(options.file, constants.F_OK)
|
||||
|
||||
console.log('Uploading %s video...', program['videoName'])
|
||||
console.log('Uploading %s video...', options.videoName)
|
||||
|
||||
const videoAttributes = await buildVideoAttributesFromCommander(url, program)
|
||||
|
||||
Object.assign(videoAttributes, {
|
||||
fixture: program['file'],
|
||||
thumbnailfile: program['thumbnail'],
|
||||
previewfile: program['preview']
|
||||
fixture: options.file,
|
||||
thumbnailfile: options.thumbnail,
|
||||
previewfile: options.preview
|
||||
})
|
||||
|
||||
try {
|
||||
await uploadVideo(url, accessToken, videoAttributes)
|
||||
console.log(`Video ${program['videoName']} uploaded.`)
|
||||
console.log(`Video ${options.videoName} uploaded.`)
|
||||
process.exit(0)
|
||||
} catch (err) {
|
||||
console.error(require('util').inspect(err))
|
||||
|
|
|
@ -8,40 +8,30 @@ import { execSync } from 'child_process'
|
|||
program
|
||||
.name('watch')
|
||||
.arguments('<url>')
|
||||
.option('-g, --gui <player>', 'player type', /^(airplay|stdout|chromecast|mpv|vlc|mplayer|xbmc)$/i, 'vlc')
|
||||
.addOption(
|
||||
new program.Option('-g, --gui <player>', 'player type')
|
||||
.default('vlc')
|
||||
.choices([ 'airplay', 'stdout', 'chromecast', 'mpv', 'vlc', 'mplayer', 'xbmc' ])
|
||||
)
|
||||
.option('-r, --resolution <res>', 'video resolution', '480')
|
||||
.on('--help', function () {
|
||||
console.log(' Available Players:')
|
||||
console.log()
|
||||
console.log(' - mpv')
|
||||
console.log(' - mplayer')
|
||||
console.log(' - vlc')
|
||||
console.log(' - stdout')
|
||||
console.log(' - xbmc')
|
||||
console.log(' - airplay')
|
||||
console.log(' - chromecast')
|
||||
console.log()
|
||||
console.log()
|
||||
console.log(' Examples:')
|
||||
console.log()
|
||||
console.log(' $ peertube watch -g mpv https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
|
||||
console.log(' $ peertube watch --gui stdout https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
|
||||
console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
|
||||
console.log()
|
||||
})
|
||||
.action((url, cmd) => run(url, cmd))
|
||||
.addHelpText('after', '\n\n Examples:\n\n' +
|
||||
' $ peertube watch -g mpv https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10\n' +
|
||||
' $ peertube watch --gui stdout https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10\n' +
|
||||
' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10\n'
|
||||
)
|
||||
.action((url, options) => run(url, options))
|
||||
.parse(process.argv)
|
||||
|
||||
function run (url: string, program: any) {
|
||||
function run (url: string, options: program.OptionValues) {
|
||||
if (!url) {
|
||||
console.error('<url> positional argument is required.')
|
||||
process.exit(-1)
|
||||
}
|
||||
|
||||
const cmd = 'node ' + join(__dirname, 'node_modules', 'webtorrent-hybrid', 'bin', 'cmd.js')
|
||||
const args = ` --${program.gui} ` +
|
||||
const args = ` --${options.gui} ` +
|
||||
url.replace('videos/watch', 'download/torrents') +
|
||||
`-${program.resolution}.torrent`
|
||||
`-${options.resolution}.torrent`
|
||||
|
||||
try {
|
||||
execSync(cmd + args)
|
||||
|
|
|
@ -69,17 +69,12 @@ getSettings()
|
|||
: 'instance ' + settings.remotes[settings.default] + ' selected'
|
||||
|
||||
program
|
||||
.on('--help', function () {
|
||||
console.log()
|
||||
console.log(' State: ' + state)
|
||||
console.log()
|
||||
console.log(' Examples:')
|
||||
console.log()
|
||||
console.log(' $ peertube auth add -u "PEERTUBE_URL" -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"')
|
||||
console.log(' $ peertube up <videoFile>')
|
||||
console.log(' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10')
|
||||
console.log()
|
||||
})
|
||||
.addHelpText('after', '\n\n State: ' + state + '\n\n' +
|
||||
' Examples:\n\n' +
|
||||
' $ peertube auth add -u "PEERTUBE_URL" -U "PEERTUBE_USER" --password "PEERTUBE_PASSWORD"\n' +
|
||||
' $ peertube up <videoFile>\n' +
|
||||
' $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10\n'
|
||||
)
|
||||
.parse(process.argv)
|
||||
})
|
||||
.catch(err => console.error(err))
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
import { NextFunction, Request, Response } from 'express'
|
||||
|
||||
export type ExpressPromiseHandler = (req: Request<any>, res: Response, next: NextFunction) => Promise<any>
|
|
@ -4,7 +4,7 @@ export class MockInstancesIndex {
|
|||
private readonly indexInstances: { host: string, createdAt: string }[] = []
|
||||
|
||||
initialize () {
|
||||
return new Promise(res => {
|
||||
return new Promise<void>(res => {
|
||||
const app = express()
|
||||
|
||||
app.use('/', (req: express.Request, res: express.Response, next: express.NextFunction) => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { ChildProcess, fork } from 'child_process'
|
||||
import { join } from 'path'
|
||||
import { randomInt } from '../../core-utils/miscs/miscs'
|
||||
import { parallelTests } from '../server/servers'
|
||||
|
||||
|
@ -10,7 +11,7 @@ class MockSmtpServer {
|
|||
private emails: object[]
|
||||
|
||||
private constructor () {
|
||||
this.emailChildProcess = fork(`${__dirname}/email-child-process`, [])
|
||||
this.emailChildProcess = fork(join(__dirname, 'email-child-process'), [])
|
||||
|
||||
this.emailChildProcess.on('message', (msg: any) => {
|
||||
if (msg.email) {
|
||||
|
@ -27,7 +28,7 @@ class MockSmtpServer {
|
|||
|
||||
if (this.started) {
|
||||
this.emails = emailsCollection
|
||||
return res()
|
||||
return res(undefined)
|
||||
}
|
||||
|
||||
// ensure maildev isn't started until
|
||||
|
|
|
@ -21,19 +21,21 @@ function reportAbuse (options: {
|
|||
}) {
|
||||
const path = '/api/v1/abuses'
|
||||
|
||||
const video = options.videoId ? {
|
||||
id: options.videoId,
|
||||
startAt: options.startAt,
|
||||
endAt: options.endAt
|
||||
} : undefined
|
||||
const video = options.videoId
|
||||
? {
|
||||
id: options.videoId,
|
||||
startAt: options.startAt,
|
||||
endAt: options.endAt
|
||||
}
|
||||
: undefined
|
||||
|
||||
const comment = options.commentId ? {
|
||||
id: options.commentId
|
||||
} : undefined
|
||||
const comment = options.commentId
|
||||
? { id: options.commentId }
|
||||
: undefined
|
||||
|
||||
const account = options.accountId ? {
|
||||
id: options.accountId
|
||||
} : undefined
|
||||
const account = options.accountId
|
||||
? { id: options.accountId }
|
||||
: undefined
|
||||
|
||||
const body = {
|
||||
account,
|
||||
|
|
|
@ -14,7 +14,7 @@ export class MockBlocklist {
|
|||
private server: Server
|
||||
|
||||
initialize () {
|
||||
return new Promise(res => {
|
||||
return new Promise<void>(res => {
|
||||
const app = express()
|
||||
|
||||
app.get('/blocklist', (req: express.Request, res: express.Response) => {
|
||||
|
|
|
@ -98,7 +98,7 @@ function sendRTMPStream (rtmpBaseUrl: string, streamKey: string, fixtureName = '
|
|||
}
|
||||
|
||||
function waitFfmpegUntilError (command: ffmpeg.FfmpegCommand, successAfterMS = 10000) {
|
||||
return new Promise((res, rej) => {
|
||||
return new Promise<void>((res, rej) => {
|
||||
command.on('error', err => {
|
||||
return rej(err)
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue