Add CLI plugins tests

pull/1987/head
Chocobozzz 2019-07-19 10:37:35 +02:00 committed by Chocobozzz
parent 32fe001389
commit 9b474844e8
22 changed files with 611 additions and 170 deletions

View File

@ -4,21 +4,16 @@ import { PluginManager } from '../../server/lib/plugins/plugin-manager'
import { isAbsolute } from 'path' import { isAbsolute } from 'path'
program program
.option('-n, --plugin-name [pluginName]', 'Plugin name to install') .option('-n, --npm-name [npmName]', 'Plugin to install')
.option('-v, --plugin-version [pluginVersion]', 'Plugin version to install') .option('-v, --plugin-version [pluginVersion]', 'Plugin version to install')
.option('-p, --plugin-path [pluginPath]', 'Path of the plugin you want to install') .option('-p, --plugin-path [pluginPath]', 'Path of the plugin you want to install')
.parse(process.argv) .parse(process.argv)
if (!program['pluginName'] && !program['pluginPath']) { if (!program['npmName'] && !program['pluginPath']) {
console.error('You need to specify a plugin name with the desired version, or a plugin path.') console.error('You need to specify a plugin name with the desired version, or a plugin path.')
process.exit(-1) process.exit(-1)
} }
if (program['pluginName'] && !program['pluginVersion']) {
console.error('You need to specify a the version of the plugin you want to install.')
process.exit(-1)
}
if (program['pluginPath'] && !isAbsolute(program['pluginPath'])) { if (program['pluginPath'] && !isAbsolute(program['pluginPath'])) {
console.error('Plugin path should be absolute.') console.error('Plugin path should be absolute.')
process.exit(-1) process.exit(-1)
@ -34,6 +29,6 @@ run()
async function run () { async function run () {
await initDatabaseModels(true) await initDatabaseModels(true)
const toInstall = program['pluginName'] || program['pluginPath'] const toInstall = program['npmName'] || program['pluginPath']
await PluginManager.Instance.install(toInstall, program['pluginVersion'], !!program['pluginPath']) await PluginManager.Instance.install(toInstall, program['pluginVersion'], !!program['pluginPath'])
} }

View File

@ -14,7 +14,8 @@ if [ "$1" = "misc" ]; then
mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/client.ts \ mocha --timeout 5000 --exit --require ts-node/register --bail server/tests/client.ts \
server/tests/feeds/index.ts \ server/tests/feeds/index.ts \
server/tests/misc-endpoints.ts \ server/tests/misc-endpoints.ts \
server/tests/helpers/index.ts server/tests/helpers/index.ts \
server/tests/plugins/index.ts
elif [ "$1" = "cli" ]; then elif [ "$1" = "cli" ]; then
npm run build:server npm run build:server
CC=gcc-4.9 CXX=g++-4.9 npm run setup:cli CC=gcc-4.9 CXX=g++-4.9 npm run setup:cli

View File

@ -4,7 +4,7 @@
*/ */
import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto' import { createHash, HexBase64Latin1Encoding, pseudoRandomBytes } from 'crypto'
import { isAbsolute, join } from 'path' import { basename, isAbsolute, join, resolve } from 'path'
import * as pem from 'pem' import * as pem from 'pem'
import { URL } from 'url' import { URL } from 'url'
import { truncate } from 'lodash' import { truncate } from 'lodash'
@ -136,16 +136,16 @@ function getAppNumber () {
return process.env.NODE_APP_INSTANCE return process.env.NODE_APP_INSTANCE
} }
let rootPath: string
function root () { function root () {
if (rootPath) return rootPath
// We are in /helpers/utils.js // We are in /helpers/utils.js
const paths = [ __dirname, '..', '..' ] rootPath = join(__dirname, '..', '..')
// We are under /dist directory if (basename(rootPath) === 'dist') rootPath = resolve(rootPath, '..')
if (process.mainModule && process.mainModule.filename.endsWith('_mocha') === false) {
paths.push('..')
}
return join.apply(null, paths) return rootPath
} }
// Thanks: https://stackoverflow.com/a/12034334 // Thanks: https://stackoverflow.com/a/12034334

View File

@ -387,14 +387,15 @@ namespace audio {
export namespace bitrate { export namespace bitrate {
const baseKbitrate = 384 const baseKbitrate = 384
const toBits = (kbits: number): number => { return kbits * 8000 } const toBits = (kbits: number) => kbits * 8000
export const aac = (bitrate: number): number => { export const aac = (bitrate: number): number => {
switch (true) { switch (true) {
case bitrate > toBits(baseKbitrate): case bitrate > toBits(baseKbitrate):
return baseKbitrate return baseKbitrate
default:
return -1 // we interpret it as a signal to copy the audio stream as is default:
return -1 // we interpret it as a signal to copy the audio stream as is
} }
} }
@ -405,12 +406,14 @@ namespace audio {
made here are not made to be accurate, especially with good mp3 encoders. made here are not made to be accurate, especially with good mp3 encoders.
*/ */
switch (true) { switch (true) {
case bitrate <= toBits(192): case bitrate <= toBits(192):
return 128 return 128
case bitrate <= toBits(384):
return 256 case bitrate <= toBits(384):
default: return 256
return baseKbitrate
default:
return baseKbitrate
} }
} }
} }

View File

@ -5,12 +5,12 @@ import { CONFIG } from '../../initializers/config'
import { outputJSON, pathExists } from 'fs-extra' import { outputJSON, pathExists } from 'fs-extra'
import { join } from 'path' import { join } from 'path'
async function installNpmPlugin (name: string, version?: string) { async function installNpmPlugin (npmName: string, version?: string) {
// Security check // Security check
checkNpmPluginNameOrThrow(name) checkNpmPluginNameOrThrow(npmName)
if (version) checkPluginVersionOrThrow(version) if (version) checkPluginVersionOrThrow(version)
let toInstall = name let toInstall = npmName
if (version) toInstall += `@${version}` if (version) toInstall += `@${version}`
await execYarn('add ' + toInstall) await execYarn('add ' + toInstall)

View File

@ -387,13 +387,24 @@ describe('Test users API validators', function () {
} }
}) })
it('Should fail with an invalid theme', async function () {
const fields = { theme: 'invalid' }
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
})
it('Should fail with an unknown theme', async function () {
const fields = { theme: 'peertube-theme-unknown' }
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields })
})
it('Should succeed to change password with the correct params', async function () { it('Should succeed to change password with the correct params', async function () {
const fields = { const fields = {
currentPassword: 'my super password', currentPassword: 'my super password',
password: 'my super password', password: 'my super password',
nsfwPolicy: 'blur', nsfwPolicy: 'blur',
autoPlayVideo: false, autoPlayVideo: false,
email: 'super_email@example.com' email: 'super_email@example.com',
theme: 'default'
} }
await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 }) await makePutBodyRequest({ url: server.url, path: path + 'me', token: userAccessToken, fields, statusCodeExpected: 204 })

View File

@ -11,3 +11,4 @@ import './reverse-proxy'
import './stats' import './stats'
import './tracker' import './tracker'
import './no-client' import './no-client'
import './plugins'

View File

@ -0,0 +1,130 @@
/* tslint:disable:no-unused-expression */
import 'mocha'
import * as chai from 'chai'
import { About } from '../../../../shared/models/server/about.model'
import { CustomConfig } from '../../../../shared/models/server/custom-config.model'
import {
cleanupTests,
deleteCustomConfig,
flushAndRunServer,
getAbout,
getConfig,
getCustomConfig, installPlugin,
killallServers, parallelTests,
registerUser,
reRunServer, ServerInfo,
setAccessTokensToServers,
updateCustomConfig, uploadVideo
} from '../../../../shared/extra-utils'
import { ServerConfig } from '../../../../shared/models'
import { PeerTubePlugin } from '../../../../shared/models/plugins/peertube-plugin.model'
const expect = chai.expect
describe('Test plugins', function () {
let server = null
before(async function () {
this.timeout(30000)
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
{
await installPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-hello-world' })
}
{
await installPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-plugin-background-color' })
}
})
it('Should list available plugins and themes', async function () {
// List without filter
// List with filter (plugin and theme)
})
it('Should search available plugins', async function () {
// Search with filter (plugin and theme)
// Add pagination
// Add sort
// Add peertube engine
})
it('Should have an empty global css', async function () {
// get /global.css
})
it('Should install a plugin and a theme', async function () {
})
it('Should have the correct global css', async function () {
// get /global.css
})
it('Should have the plugin loaded in the configuration', async function () {
// Check registered themes/plugins
})
it('Should update the default theme in the configuration', async function () {
// Update config
})
it('Should list plugins and themes', async function () {
// List without filter
// List with filter (theme/plugin)
// List with pagination
// List with sort
})
it('Should get a plugin and a theme', async function () {
// Get plugin
// Get theme
})
it('Should get registered settings', async function () {
// Get plugin
})
it('Should update the settings', async function () {
// Update /settings
// get /plugin
})
it('Should update the plugin and the theme', async function () {
// update BDD -> 0.0.1
// update package.json (theme + plugin)
// list to check versions
// update plugin + theme
// list to check they have been updated
// check package.json are upgraded too
})
it('Should uninstall the plugin', async function () {
// uninstall
// list
})
it('Should have an empty global css', async function () {
// get /global.css
})
it('Should list uninstalled plugins', async function () {
// { uninstalled: true }
})
it('Should uninstall the theme', async function () {
// Uninstall
})
it('Should have updated the configuration', async function () {
// get /config (default theme + registered themes + registered plugins)
})
after(async function () {
await cleanupTests([ server ])
})
})

View File

@ -18,7 +18,7 @@ import {
getUsersList, getUsersList,
getUsersListPaginationAndSort, getUsersListPaginationAndSort,
getVideoChannel, getVideoChannel,
getVideosList, getVideosList, installPlugin,
login, login,
makePutBodyRequest, makePutBodyRequest,
rateVideo, rateVideo,
@ -57,6 +57,8 @@ describe('Test users', function () {
server = await flushAndRunServer(1) server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ]) await setAccessTokensToServers([ server ])
await installPlugin({ url: server.url, accessToken: server.accessToken, npmName: 'peertube-theme-background-red' })
}) })
describe('OAuth client', function () { describe('OAuth client', function () {
@ -551,6 +553,21 @@ describe('Test users', function () {
expect(user.account.displayName).to.equal('new display name') expect(user.account.displayName).to.equal('new display name')
expect(user.account.description).to.equal('my super description updated') expect(user.account.description).to.equal('my super description updated')
}) })
it('Should be able to update my theme', async function () {
for (const theme of [ 'background-red', 'default', 'instance-default' ]) {
await updateMyUser({
url: server.url,
accessToken: accessTokenUser,
theme
})
const res = await getMyUserInformation(server.url, accessTokenUser)
const body: User = res.body
expect(body.theme).to.equal(theme)
}
})
}) })
describe('Updating another user', function () { describe('Updating another user', function () {

View File

@ -3,5 +3,6 @@ import './create-import-video-file-job'
import './create-transcoding-job' import './create-transcoding-job'
import './optimize-old-videos' import './optimize-old-videos'
import './peertube' import './peertube'
import './plugins'
import './reset-password' import './reset-password'
import './update-host' import './update-host'

View File

@ -43,133 +43,171 @@ describe('Test CLI wrapper', function () {
} }
}) })
it('Should display no selected instance', async function () { describe('Authentication and instance selection', function () {
this.timeout(60000)
const env = getEnvCli(server) it('Should display no selected instance', async function () {
const stdout = await execCLI(`${env} ${cmd} --help`) this.timeout(60000)
expect(stdout).to.contain('no instance selected') const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain('no instance selected')
})
it('Should add a user', async function () {
this.timeout(60000)
const env = getEnvCli(server)
await execCLI(`${env} ${cmd} auth add -u ${server.url} -U user_1 -p super_password`)
})
it('Should default to this user', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain(`instance ${server.url} selected`)
})
it('Should remember the user', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} auth list`)
expect(stdout).to.contain(server.url)
})
}) })
it('Should add a user', async function () { describe('Video upload/import', function () {
this.timeout(60000)
const env = getEnvCli(server) it('Should upload a video', async function () {
await execCLI(`${env} ${cmd} auth add -u ${server.url} -U user_1 -p super_password`) this.timeout(60000)
})
it('Should default to this user', async function () { const env = getEnvCli(server)
this.timeout(60000)
const env = getEnvCli(server) const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4')
const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain(`instance ${server.url} selected`) const params = `-f ${fixture} --video-name 'test upload' --channel-name user_channel --support 'support_text'`
})
it('Should remember the user', async function () { await execCLI(`${env} ${cmd} upload ${params}`)
this.timeout(60000) })
const env = getEnvCli(server) it('Should have the video uploaded', async function () {
const stdout = await execCLI(`${env} ${cmd} auth list`)
expect(stdout).to.contain(server.url)
})
it('Should upload a video', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4')
const params = `-f ${fixture} --video-name 'test upload' --channel-name user_channel --support 'support_text'`
await execCLI(`${env} ${cmd} upload ${params}`)
})
it('Should have the video uploaded', async function () {
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(1)
const videos: Video[] = res.body.data
const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body
expect(video.name).to.equal('test upload')
expect(video.support).to.equal('support_text')
expect(video.channel.name).to.equal('user_channel')
})
it('Should import a video', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel`
await execCLI(`${env} ${cmd} import ${params}`)
})
it('Should have imported the video', async function () {
this.timeout(60000)
await waitJobs([ server ])
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2)
const videos: Video[] = res.body.data
const video = videos.find(v => v.name === 'small video - youtube')
expect(video).to.not.be.undefined
const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body
expect(videoDetails.channel.name).to.equal('user_channel')
expect(videoDetails.support).to.equal('super support text')
expect(videoDetails.nsfw).to.be.false
// So we can reimport it
await removeVideo(server.url, userAccessToken, video.id)
})
it('Should import and override some imported attributes', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel --video-name toto --nsfw --support support`
await execCLI(`${env} ${cmd} import ${params}`)
await waitJobs([ server ])
{
const res = await getVideosList(server.url) const res = await getVideosList(server.url)
expect(res.body.total).to.equal(1)
const videos: Video[] = res.body.data
const video: VideoDetails = (await getVideo(server.url, videos[ 0 ].uuid)).body
expect(video.name).to.equal('test upload')
expect(video.support).to.equal('support_text')
expect(video.channel.name).to.equal('user_channel')
})
it('Should import a video', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel`
await execCLI(`${env} ${cmd} import ${params}`)
})
it('Should have imported the video', async function () {
this.timeout(60000)
await waitJobs([ server ])
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2) expect(res.body.total).to.equal(2)
const videos: Video[] = res.body.data const videos: Video[] = res.body.data
const video = videos.find(v => v.name === 'toto') const video = videos.find(v => v.name === 'small video - youtube')
expect(video).to.not.be.undefined expect(video).to.not.be.undefined
const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body
expect(videoDetails.channel.name).to.equal('user_channel') expect(videoDetails.channel.name).to.equal('user_channel')
expect(videoDetails.support).to.equal('support') expect(videoDetails.support).to.equal('super support text')
expect(videoDetails.nsfw).to.be.true expect(videoDetails.nsfw).to.be.false
expect(videoDetails.commentsEnabled).to.be.true
} // So we can reimport it
await removeVideo(server.url, userAccessToken, video.id)
})
it('Should import and override some imported attributes', async function () {
this.timeout(60000)
const env = getEnvCli(server)
const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel --video-name toto --nsfw --support support`
await execCLI(`${env} ${cmd} import ${params}`)
await waitJobs([ server ])
{
const res = await getVideosList(server.url)
expect(res.body.total).to.equal(2)
const videos: Video[] = res.body.data
const video = videos.find(v => v.name === 'toto')
expect(video).to.not.be.undefined
const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body
expect(videoDetails.channel.name).to.equal('user_channel')
expect(videoDetails.support).to.equal('support')
expect(videoDetails.nsfw).to.be.true
expect(videoDetails.commentsEnabled).to.be.true
}
})
}) })
it('Should remove the auth user', async function () { describe('Admin auth', function () {
const env = getEnvCli(server)
await execCLI(`${env} ${cmd} auth del ${server.url}`) it('Should remove the auth user', async function () {
const env = getEnvCli(server)
const stdout = await execCLI(`${env} ${cmd} --help`) await execCLI(`${env} ${cmd} auth del ${server.url}`)
expect(stdout).to.contain('no instance selected') const stdout = await execCLI(`${env} ${cmd} --help`)
expect(stdout).to.contain('no instance selected')
})
it('Should add the admin user', async function () {
const env = getEnvCli(server)
await execCLI(`${env} ${cmd} auth add -u ${server.url} -U root -p test${server.internalServerNumber}`)
})
})
describe('Manage plugins', function () {
it('Should install a plugin', async function () {
this.timeout(60000)
const env = getEnvCli(server)
await execCLI(`${env} ${cmd} plugins install --npm-name peertube-plugin-hello-world`)
})
it('Should list installed plugins', async function () {
const env = getEnvCli(server)
const res = await execCLI(`${env} ${cmd} plugins list`)
expect(res).to.contain('peertube-plugin-hello-world')
})
it('Should uninstall the plugin', async function () {
const env = getEnvCli(server)
const res = await execCLI(`${env} ${cmd} plugins uninstall --npm-name peertube-plugin-hello-world`)
expect(res).to.not.contain('peertube-plugin-hello-world')
})
}) })
after(async function () { after(async function () {

View File

@ -0,0 +1,87 @@
/* tslint:disable:no-unused-expression */
import 'mocha'
import {
cleanupTests,
execCLI,
flushAndRunServer,
getConfig,
getEnvCli, killallServers,
reRunServer,
root,
ServerInfo,
setAccessTokensToServers
} from '../../../shared/extra-utils'
import { join } from 'path'
import { ServerConfig } from '../../../shared/models/server'
import { expect } from 'chai'
describe('Test plugin scripts', function () {
let server: ServerInfo
before(async function () {
this.timeout(30000)
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
})
it('Should install a plugin from stateless CLI', async function () {
this.timeout(60000)
const packagePath = join(root(), 'server', 'tests', 'fixtures', 'peertube-plugin-test')
const env = getEnvCli(server)
await execCLI(`${env} npm run plugin:install -- --plugin-path ${packagePath}`)
})
it('Should install a theme from stateless CLI', async function () {
this.timeout(60000)
const env = getEnvCli(server)
await execCLI(`${env} npm run plugin:install -- --npm-name peertube-theme-background-red`)
})
it('Should have the theme and the plugin registered when we restart peertube', async function () {
this.timeout(30000)
killallServers([ server ])
await reRunServer(server)
const res = await getConfig(server.url)
const config: ServerConfig = res.body
const plugin = config.plugin.registered
.find(p => p.name === 'test')
expect(plugin).to.not.be.undefined
const theme = config.theme.registered
.find(t => t.name === 'background-red')
expect(theme).to.not.be.undefined
})
it('Should uninstall a plugin from stateless CLI', async function () {
this.timeout(60000)
const env = getEnvCli(server)
await execCLI(`${env} npm run plugin:uninstall -- --npm-name peertube-plugin-test`)
})
it('Should have removed the plugin on another peertube restart', async function () {
this.timeout(30000)
killallServers([ server ])
await reRunServer(server)
const res = await getConfig(server.url)
const config: ServerConfig = res.body
const plugin = config.plugin.registered
.find(p => p.name === 'test')
expect(plugin).to.be.undefined
})
after(async function () {
await cleanupTests([ server ])
})
})

View File

@ -0,0 +1,39 @@
async function register ({ registerHook, registerSetting, settingsManager, storageManager }) {
const defaultAdmin = 'PeerTube admin'
registerHook({
target: 'action:application.listening',
handler: () => displayHelloWorld(settingsManager, defaultAdmin)
})
registerSetting({
name: 'admin-name',
label: 'Admin name',
type: 'input',
default: defaultAdmin
})
const value = await storageManager.getData('toto')
console.log(value)
console.log(value.coucou)
await storageManager.storeData('toto', { coucou: 'hello' + new Date() })
}
async function unregister () {
return
}
module.exports = {
register,
unregister
}
// ############################################################################
async function displayHelloWorld (settingsManager, defaultAdmin) {
let value = await settingsManager.getSetting('admin-name')
if (!value) value = defaultAdmin
console.log('hello world ' + value)
}

View File

@ -0,0 +1,19 @@
{
"name": "peertube-plugin-test",
"version": "0.0.1",
"description": "Plugin test",
"engine": {
"peertube": ">=1.3.0"
},
"keywords": [
"peertube",
"plugin"
],
"homepage": "https://github.com/Chocobozzz/PeerTube",
"author": "Chocobozzz",
"bugs": "https://github.com/Chocobozzz/PeerTube/issues",
"library": "./main.js",
"staticDirs": {},
"css": [],
"clientScripts": []
}

View File

@ -3,3 +3,4 @@ import './client'
import './feeds/' import './feeds/'
import './cli/' import './cli/'
import './api/' import './api/'
import './plugins/'

View File

@ -0,0 +1,27 @@
/* tslint:disable:no-unused-expression */
import * as chai from 'chai'
import 'mocha'
import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
import { setAccessTokensToServers } from '../../../shared/extra-utils'
const expect = chai.expect
describe('Test plugin filter hooks', function () {
let server: ServerInfo
before(async function () {
this.timeout(30000)
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
})
it('Should execute ', async function () {
})
after(async function () {
await cleanupTests([ server ])
})
})

View File

@ -0,0 +1,27 @@
/* tslint:disable:no-unused-expression */
import * as chai from 'chai'
import 'mocha'
import { cleanupTests, flushAndRunServer, ServerInfo } from '../../../shared/extra-utils/server/servers'
import { setAccessTokensToServers } from '../../../shared/extra-utils'
const expect = chai.expect
describe('Test plugin filter hooks', function () {
let server: ServerInfo
before(async function () {
this.timeout(30000)
server = await flushAndRunServer(1)
await setAccessTokensToServers([ server ])
})
it('Should execute ', async function () {
})
after(async function () {
await cleanupTests([ server ])
})
})

View File

@ -0,0 +1,2 @@
export * from './action-hooks'
export * from './filter-hooks'

View File

@ -18,7 +18,7 @@ program
.command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token') .command('get-access-token', 'get a peertube access token', { noHelp: true }).alias('token')
.command('watch', 'watch a video in the terminal ✩°。⋆').alias('w') .command('watch', 'watch a video in the terminal ✩°。⋆').alias('w')
.command('repl', 'initiate a REPL to access internals') .command('repl', 'initiate a REPL to access internals')
.command('plugins [action]', 'manage plugins on a local instance').alias('p') .command('plugins [action]', 'manage instance plugins/themes').alias('p')
/* Not Yet Implemented */ /* Not Yet Implemented */
program program

View File

@ -6,6 +6,7 @@ import { UserRegister } from '../../models/users/user-register.model'
import { UserRole } from '../../models/users/user-role' import { UserRole } from '../../models/users/user-role'
import { ServerInfo } from '../server/servers' import { ServerInfo } from '../server/servers'
import { userLogin } from './login' import { userLogin } from './login'
import { UserUpdateMe } from '../../models/users'
type CreateUserArgs = { url: string, type CreateUserArgs = { url: string,
accessToken: string, accessToken: string,
@ -224,19 +225,21 @@ function updateMyUser (options: {
displayName?: string displayName?: string
description?: string description?: string
videosHistoryEnabled?: boolean videosHistoryEnabled?: boolean
theme?: string
}) { }) {
const path = '/api/v1/users/me' const path = '/api/v1/users/me'
const toSend = {} const toSend: UserUpdateMe = {}
if (options.currentPassword !== undefined && options.currentPassword !== null) toSend['currentPassword'] = options.currentPassword if (options.currentPassword !== undefined && options.currentPassword !== null) toSend.currentPassword = options.currentPassword
if (options.newPassword !== undefined && options.newPassword !== null) toSend['password'] = options.newPassword if (options.newPassword !== undefined && options.newPassword !== null) toSend.password = options.newPassword
if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend['nsfwPolicy'] = options.nsfwPolicy if (options.nsfwPolicy !== undefined && options.nsfwPolicy !== null) toSend.nsfwPolicy = options.nsfwPolicy
if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend['autoPlayVideo'] = options.autoPlayVideo if (options.autoPlayVideo !== undefined && options.autoPlayVideo !== null) toSend.autoPlayVideo = options.autoPlayVideo
if (options.email !== undefined && options.email !== null) toSend['email'] = options.email if (options.email !== undefined && options.email !== null) toSend.email = options.email
if (options.description !== undefined && options.description !== null) toSend['description'] = options.description if (options.description !== undefined && options.description !== null) toSend.description = options.description
if (options.displayName !== undefined && options.displayName !== null) toSend['displayName'] = options.displayName if (options.displayName !== undefined && options.displayName !== null) toSend.displayName = options.displayName
if (options.theme !== undefined && options.theme !== null) toSend.theme = options.theme
if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) { if (options.videosHistoryEnabled !== undefined && options.videosHistoryEnabled !== null) {
toSend['videosHistoryEnabled'] = options.videosHistoryEnabled toSend.videosHistoryEnabled = options.videosHistoryEnabled
} }
return makePutBodyRequest({ return makePutBodyRequest({

View File

@ -18,30 +18,35 @@ export enum VideoResolution {
*/ */
function getBaseBitrate (resolution: VideoResolution) { function getBaseBitrate (resolution: VideoResolution) {
switch (resolution) { switch (resolution) {
case VideoResolution.H_240P: case VideoResolution.H_240P:
// quality according to Google Live Encoder: 300 - 700 Kbps // quality according to Google Live Encoder: 300 - 700 Kbps
// Quality according to YouTube Video Info: 186 Kbps // Quality according to YouTube Video Info: 186 Kbps
return 250 * 1000 return 250 * 1000
case VideoResolution.H_360P:
// quality according to Google Live Encoder: 400 - 1,000 Kbps case VideoResolution.H_360P:
// Quality according to YouTube Video Info: 480 Kbps // quality according to Google Live Encoder: 400 - 1,000 Kbps
return 500 * 1000 // Quality according to YouTube Video Info: 480 Kbps
case VideoResolution.H_480P: return 500 * 1000
// quality according to Google Live Encoder: 500 - 2,000 Kbps
// Quality according to YouTube Video Info: 879 Kbps case VideoResolution.H_480P:
return 900 * 1000 // quality according to Google Live Encoder: 500 - 2,000 Kbps
case VideoResolution.H_720P: // Quality according to YouTube Video Info: 879 Kbps
// quality according to Google Live Encoder: 1,500 - 4,000 Kbps return 900 * 1000
// Quality according to YouTube Video Info: 1752 Kbps
return 1750 * 1000 case VideoResolution.H_720P:
case VideoResolution.H_1080P: // quality according to Google Live Encoder: 1,500 - 4,000 Kbps
// quality according to Google Live Encoder: 3000 - 6000 Kbps // Quality according to YouTube Video Info: 1752 Kbps
// Quality according to YouTube Video Info: 3277 Kbps return 1750 * 1000
return 3300 * 1000
case VideoResolution.H_4K: // fallthrough case VideoResolution.H_1080P:
default: // quality according to Google Live Encoder: 3000 - 6000 Kbps
// quality according to Google Live Encoder: 13000 - 34000 Kbps // Quality according to YouTube Video Info: 3277 Kbps
return 15000 * 1000 return 3300 * 1000
case VideoResolution.H_4K: // fallthrough
default:
// quality according to Google Live Encoder: 13000 - 34000 Kbps
return 15000 * 1000
} }
} }

View File

@ -75,6 +75,7 @@ You can access it as `peertube` via an alias in your `.bashrc` like `alias peert
import-videos|import import a video from a streaming platform import-videos|import import a video from a streaming platform
watch|w watch a video in the terminal ✩°。⋆ watch|w watch a video in the terminal ✩°。⋆
repl initiate a REPL to access internals repl initiate a REPL to access internals
plugins|p [action] manag instance plugins
help [cmd] display help for [cmd] help [cmd] display help for [cmd]
``` ```
@ -102,6 +103,15 @@ And now that your video is online, you can watch it from the confort of your ter
$ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10 $ peertube watch https://peertube.cpy.re/videos/watch/e8a1af4e-414a-4d58-bfe6-2146eed06d10
``` ```
To list, install, uninstall dynamically plugins/themes of an instance:
```bash
$ peertube plugins list
$ peertube plugins install --path /local/plugin/path
$ peertube plugins install --npm-name peertube-plugin-myplugin
$ peertube plugins uninstall --npm-name peertube-plugin-myplugin
```
#### peertube-import-videos.js #### peertube-import-videos.js
You can use this script to import videos from all [supported sites of youtube-dl](https://rg3.github.io/youtube-dl/supportedsites.html) into PeerTube. You can use this script to import videos from all [supported sites of youtube-dl](https://rg3.github.io/youtube-dl/supportedsites.html) into PeerTube.
@ -233,6 +243,30 @@ To reset a user password from CLI, run:
$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u target_username $ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run reset-password -- -u target_username
``` ```
### plugin install/uninstall
The difference with `peertube plugins` CLI is that these scripts can be used even if PeerTube is not running.
If PeerTube is running, you need to restart it for the changes to take effect (whereas with `peertube plugins` CLI, plugins/themes are dynamically loaded on the server).
To install a plugin or a theme from the disk:
```
$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run npm run plugin:install -- --plugin-path /local/plugin/path
```
From NPM:
```
$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run npm run plugin:install -- --npm-name peertube-plugin-myplugin
```
To uninstall a plugin or a theme:
```
$ sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production npm run npm run plugin:uninstall -- --npm-name peertube-plugin-myplugin
```
### REPL ([Read Eval Print Loop](https://nodejs.org/docs/latest-v8.x/api/repl.html)) ### REPL ([Read Eval Print Loop](https://nodejs.org/docs/latest-v8.x/api/repl.html))
If you want to interact with the application libraries and objects even when PeerTube is not running, there is a REPL for that. If you want to interact with the application libraries and objects even when PeerTube is not running, there is a REPL for that.