diff options
-rw-r--r-- | server/tests/cli/peertube.ts | 64 | ||||
-rw-r--r-- | server/tools/cli.ts | 69 | ||||
-rw-r--r-- | server/tools/peertube-import-videos.ts | 38 | ||||
-rw-r--r-- | server/tools/peertube-upload.ts | 52 |
4 files changed, 151 insertions, 72 deletions
diff --git a/server/tests/cli/peertube.ts b/server/tests/cli/peertube.ts index 6e7bf0843..0a8a98334 100644 --- a/server/tests/cli/peertube.ts +++ b/server/tests/cli/peertube.ts | |||
@@ -10,18 +10,20 @@ import { | |||
10 | execCLI, | 10 | execCLI, |
11 | flushAndRunServer, | 11 | flushAndRunServer, |
12 | getEnvCli, | 12 | getEnvCli, |
13 | getMyUserInformation, | 13 | getVideo, |
14 | getVideosList, | 14 | getVideosList, |
15 | getVideosListWithToken, removeVideo, | ||
15 | ServerInfo, | 16 | ServerInfo, |
16 | setAccessTokensToServers, | 17 | setAccessTokensToServers, |
17 | userLogin, waitJobs | 18 | userLogin, |
19 | waitJobs | ||
18 | } from '../../../shared/extra-utils' | 20 | } from '../../../shared/extra-utils' |
19 | import { User, Video } from '../../../shared' | 21 | import { Video, VideoDetails } from '../../../shared' |
20 | import { getYoutubeVideoUrl } from '../../../shared/extra-utils/videos/video-imports' | 22 | import { getYoutubeVideoUrl } from '../../../shared/extra-utils/videos/video-imports' |
21 | 23 | ||
22 | describe('Test CLI wrapper', function () { | 24 | describe('Test CLI wrapper', function () { |
23 | let server: ServerInfo | 25 | let server: ServerInfo |
24 | let channelId: number | 26 | let userAccessToken: string |
25 | 27 | ||
26 | const cmd = 'node ./dist/server/tools/peertube.js' | 28 | const cmd = 'node ./dist/server/tools/peertube.js' |
27 | 29 | ||
@@ -33,11 +35,11 @@ describe('Test CLI wrapper', function () { | |||
33 | 35 | ||
34 | await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super_password' }) | 36 | await createUser({ url: server.url, accessToken: server.accessToken, username: 'user_1', password: 'super_password' }) |
35 | 37 | ||
36 | const userAccessToken = await userLogin(server, { username: 'user_1', password: 'super_password' }) | 38 | userAccessToken = await userLogin(server, { username: 'user_1', password: 'super_password' }) |
37 | 39 | ||
38 | { | 40 | { |
39 | const res = await addVideoChannel(server.url, userAccessToken, { name: 'user_channel', displayName: 'User channel' }) | 41 | const args = { name: 'user_channel', displayName: 'User channel', support: 'super support text' } |
40 | channelId = res.body.videoChannel.id | 42 | await addVideoChannel(server.url, userAccessToken, args) |
41 | } | 43 | } |
42 | }) | 44 | }) |
43 | 45 | ||
@@ -82,7 +84,7 @@ describe('Test CLI wrapper', function () { | |||
82 | 84 | ||
83 | const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4') | 85 | const fixture = buildAbsoluteFixturePath('60fps_720p_small.mp4') |
84 | 86 | ||
85 | const params = `-f ${fixture} --video-name 'test upload' --channel-id ${channelId}` | 87 | const params = `-f ${fixture} --video-name 'test upload' --channel-name user_channel --support 'support_text'` |
86 | 88 | ||
87 | await execCLI(`${env} ${cmd} upload ${params}`) | 89 | await execCLI(`${env} ${cmd} upload ${params}`) |
88 | }) | 90 | }) |
@@ -93,8 +95,12 @@ describe('Test CLI wrapper', function () { | |||
93 | expect(res.body.total).to.equal(1) | 95 | expect(res.body.total).to.equal(1) |
94 | 96 | ||
95 | const videos: Video[] = res.body.data | 97 | const videos: Video[] = res.body.data |
96 | expect(videos[0].name).to.equal('test upload') | 98 | |
97 | expect(videos[0].channel.name).to.equal('user_channel') | 99 | const video: VideoDetails = (await getVideo(server.url, videos[0].uuid)).body |
100 | |||
101 | expect(video.name).to.equal('test upload') | ||
102 | expect(video.support).to.equal('support_text') | ||
103 | expect(video.channel.name).to.equal('user_channel') | ||
98 | }) | 104 | }) |
99 | 105 | ||
100 | it('Should import a video', async function () { | 106 | it('Should import a video', async function () { |
@@ -102,7 +108,7 @@ describe('Test CLI wrapper', function () { | |||
102 | 108 | ||
103 | const env = getEnvCli(server) | 109 | const env = getEnvCli(server) |
104 | 110 | ||
105 | const params = `--target-url ${getYoutubeVideoUrl()} --channel-id ${channelId}` | 111 | const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel` |
106 | 112 | ||
107 | await execCLI(`${env} ${cmd} import ${params}`) | 113 | await execCLI(`${env} ${cmd} import ${params}`) |
108 | }) | 114 | }) |
@@ -118,9 +124,41 @@ describe('Test CLI wrapper', function () { | |||
118 | 124 | ||
119 | const videos: Video[] = res.body.data | 125 | const videos: Video[] = res.body.data |
120 | const video = videos.find(v => v.name === 'small video - youtube') | 126 | const video = videos.find(v => v.name === 'small video - youtube') |
121 | |||
122 | expect(video).to.not.be.undefined | 127 | expect(video).to.not.be.undefined |
123 | expect(video.channel.name).to.equal('user_channel') | 128 | |
129 | const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body | ||
130 | expect(videoDetails.channel.name).to.equal('user_channel') | ||
131 | expect(videoDetails.support).to.equal('super support text') | ||
132 | expect(videoDetails.nsfw).to.be.false | ||
133 | |||
134 | // So we can reimport it | ||
135 | await removeVideo(server.url, userAccessToken, video.id) | ||
136 | }) | ||
137 | |||
138 | it('Should import and override some imported attributes', async function () { | ||
139 | this.timeout(60000) | ||
140 | |||
141 | const env = getEnvCli(server) | ||
142 | |||
143 | const params = `--target-url ${getYoutubeVideoUrl()} --channel-name user_channel --video-name toto --nsfw --support support` | ||
144 | |||
145 | await execCLI(`${env} ${cmd} import ${params}`) | ||
146 | |||
147 | await waitJobs([ server ]) | ||
148 | |||
149 | { | ||
150 | const res = await getVideosList(server.url) | ||
151 | expect(res.body.total).to.equal(2) | ||
152 | |||
153 | const videos: Video[] = res.body.data | ||
154 | const video = videos.find(v => v.name === 'toto') | ||
155 | expect(video).to.not.be.undefined | ||
156 | |||
157 | const videoDetails: VideoDetails = (await getVideo(server.url, video.id)).body | ||
158 | expect(videoDetails.channel.name).to.equal('user_channel') | ||
159 | expect(videoDetails.support).to.equal('support') | ||
160 | expect(videoDetails.nsfw).to.be.true | ||
161 | } | ||
124 | }) | 162 | }) |
125 | 163 | ||
126 | it('Should remove the auth user', async function () { | 164 | it('Should remove the auth user', async function () { |
diff --git a/server/tools/cli.ts b/server/tools/cli.ts index 6be558d7b..4aa3d9ce8 100644 --- a/server/tools/cli.ts +++ b/server/tools/cli.ts | |||
@@ -1,7 +1,9 @@ | |||
1 | import { Netrc } from 'netrc-parser' | 1 | import { Netrc } from 'netrc-parser' |
2 | import { isTestInstance, getAppNumber } from '../helpers/core-utils' | 2 | import { getAppNumber, isTestInstance } from '../helpers/core-utils' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { root } from '../../shared/extra-utils' | 4 | import { getVideoChannel, root } from '../../shared/extra-utils' |
5 | import { Command } from 'commander' | ||
6 | import { VideoChannel, VideoPrivacy } from '../../shared/models/videos' | ||
5 | 7 | ||
6 | let configName = 'PeerTube/CLI' | 8 | let configName = 'PeerTube/CLI' |
7 | if (isTestInstance()) configName += `-${getAppNumber()}` | 9 | if (isTestInstance()) configName += `-${getAppNumber()}` |
@@ -94,6 +96,64 @@ function getRemoteObjectOrDie (program: any, settings: Settings, netrc: Netrc) { | |||
94 | } | 96 | } |
95 | } | 97 | } |
96 | 98 | ||
99 | function buildCommonVideoOptions (command: Command) { | ||
100 | function list (val) { | ||
101 | return val.split(',') | ||
102 | } | ||
103 | |||
104 | return command | ||
105 | .option('-n, --video-name <name>', 'Video name') | ||
106 | .option('-c, --category <category_number>', 'Category number') | ||
107 | .option('-l, --licence <licence_number>', 'Licence number') | ||
108 | .option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)') | ||
109 | .option('-t, --tags <tags>', 'Video tags', list) | ||
110 | .option('-N, --nsfw', 'Video is Not Safe For Work') | ||
111 | .option('-d, --video-description <description>', 'Video description') | ||
112 | .option('-P, --privacy <privacy_number>', 'Privacy') | ||
113 | .option('-C, --channel-name <channel_name>', 'Channel name') | ||
114 | .option('-m, --comments-enabled', 'Enable comments') | ||
115 | .option('-s, --support <support>', 'Video support text') | ||
116 | .option('-w, --wait-transcoding', 'Wait transcoding before publishing the video') | ||
117 | } | ||
118 | |||
119 | async function buildVideoAttributesFromCommander (url: string, command: Command, defaultAttributes: any) { | ||
120 | const booleanAttributes: { [id: string]: boolean } = {} | ||
121 | |||
122 | for (const key of [ 'nsfw', 'commentsEnabled', 'downloadEnabled', 'waitTranscoding' ]) { | ||
123 | if (command[ key ] !== undefined) { | ||
124 | booleanAttributes[key] = command[ key ] | ||
125 | } else if (defaultAttributes[key] !== undefined) { | ||
126 | booleanAttributes[key] = defaultAttributes[key] | ||
127 | } else { | ||
128 | booleanAttributes[key] = false | ||
129 | } | ||
130 | } | ||
131 | |||
132 | const videoAttributes = { | ||
133 | name: command[ 'videoName' ] || defaultAttributes.name, | ||
134 | category: command[ 'category' ] || defaultAttributes.category || undefined, | ||
135 | licence: command[ 'licence' ] || defaultAttributes.licence || undefined, | ||
136 | language: command[ 'language' ] || defaultAttributes.language || undefined, | ||
137 | privacy: command[ 'privacy' ] || defaultAttributes.privacy || VideoPrivacy.PUBLIC, | ||
138 | support: command[ 'support' ] || defaultAttributes.support || undefined | ||
139 | } | ||
140 | |||
141 | Object.assign(videoAttributes, booleanAttributes) | ||
142 | |||
143 | if (command[ 'channelName' ]) { | ||
144 | const res = await getVideoChannel(url, command['channelName']) | ||
145 | const videoChannel: VideoChannel = res.body | ||
146 | |||
147 | Object.assign(videoAttributes, { channelId: videoChannel.id }) | ||
148 | |||
149 | if (!videoAttributes.support && videoChannel.support) { | ||
150 | Object.assign(videoAttributes, { support: videoChannel.support }) | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return videoAttributes | ||
155 | } | ||
156 | |||
97 | // --------------------------------------------------------------------------- | 157 | // --------------------------------------------------------------------------- |
98 | 158 | ||
99 | export { | 159 | export { |
@@ -103,5 +163,8 @@ export { | |||
103 | getNetrc, | 163 | getNetrc, |
104 | getRemoteObjectOrDie, | 164 | getRemoteObjectOrDie, |
105 | writeSettings, | 165 | writeSettings, |
106 | deleteSettings | 166 | deleteSettings, |
167 | |||
168 | buildCommonVideoOptions, | ||
169 | buildVideoAttributesFromCommander | ||
107 | } | 170 | } |
diff --git a/server/tools/peertube-import-videos.ts b/server/tools/peertube-import-videos.ts index f9cd3106a..d7bb00e02 100644 --- a/server/tools/peertube-import-videos.ts +++ b/server/tools/peertube-import-videos.ts | |||
@@ -3,7 +3,6 @@ require('tls').DEFAULT_ECDH_CURVE = 'auto' | |||
3 | 3 | ||
4 | import * as program from 'commander' | 4 | import * as program from 'commander' |
5 | import { join } from 'path' | 5 | import { join } from 'path' |
6 | import { VideoPrivacy } from '../../shared/models/videos' | ||
7 | import { doRequestAndSaveToFile } from '../helpers/requests' | 6 | import { doRequestAndSaveToFile } from '../helpers/requests' |
8 | import { CONSTRAINTS_FIELDS } from '../initializers/constants' | 7 | import { CONSTRAINTS_FIELDS } from '../initializers/constants' |
9 | import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/extra-utils/index' | 8 | import { getClient, getVideoCategories, login, searchVideoWithSort, uploadVideo } from '../../shared/extra-utils/index' |
@@ -12,7 +11,7 @@ import * as prompt from 'prompt' | |||
12 | import { remove } from 'fs-extra' | 11 | import { remove } from 'fs-extra' |
13 | import { sha256 } from '../helpers/core-utils' | 12 | import { sha256 } from '../helpers/core-utils' |
14 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' | 13 | import { buildOriginallyPublishedAt, safeGetYoutubeDL } from '../helpers/youtube-dl' |
15 | import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli' | 14 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli' |
16 | 15 | ||
17 | type UserInfo = { | 16 | type UserInfo = { |
18 | username: string | 17 | username: string |
@@ -24,14 +23,16 @@ const processOptions = { | |||
24 | maxBuffer: Infinity | 23 | maxBuffer: Infinity |
25 | } | 24 | } |
26 | 25 | ||
27 | program | 26 | let command = program |
28 | .name('import-videos') | 27 | .name('import-videos') |
28 | |||
29 | command = buildCommonVideoOptions(command) | ||
30 | |||
31 | command | ||
29 | .option('-u, --url <url>', 'Server url') | 32 | .option('-u, --url <url>', 'Server url') |
30 | .option('-U, --username <username>', 'Username') | 33 | .option('-U, --username <username>', 'Username') |
31 | .option('-p, --password <token>', 'Password') | 34 | .option('-p, --password <token>', 'Password') |
32 | .option('-t, --target-url <targetUrl>', 'Video target URL') | 35 | .option('-t, --target-url <targetUrl>', 'Video target URL') |
33 | .option('-C, --channel-id <channel_id>', 'Channel ID') | ||
34 | .option('-l, --language <languageCode>', 'Language ISO 639 code (fr or en...)') | ||
35 | .option('-v, --verbose', 'Verbose mode') | 36 | .option('-v, --verbose', 'Verbose mode') |
36 | .parse(process.argv) | 37 | .parse(process.argv) |
37 | 38 | ||
@@ -179,7 +180,7 @@ async function uploadVideoOnPeerTube (parameters: { | |||
179 | 180 | ||
180 | const originallyPublishedAt = buildOriginallyPublishedAt(videoInfo) | 181 | const originallyPublishedAt = buildOriginallyPublishedAt(videoInfo) |
181 | 182 | ||
182 | const videoAttributes = { | 183 | const defaultAttributes = { |
183 | name: truncate(videoInfo.title, { | 184 | name: truncate(videoInfo.title, { |
184 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, | 185 | 'length': CONSTRAINTS_FIELDS.VIDEOS.NAME.max, |
185 | 'separator': /,? +/, | 186 | 'separator': /,? +/, |
@@ -187,24 +188,19 @@ async function uploadVideoOnPeerTube (parameters: { | |||
187 | }), | 188 | }), |
188 | category, | 189 | category, |
189 | licence, | 190 | licence, |
190 | language: program[ 'language' ], | ||
191 | nsfw: isNSFW(videoInfo), | 191 | nsfw: isNSFW(videoInfo), |
192 | waitTranscoding: true, | 192 | description: videoInfo.description, |
193 | commentsEnabled: true, | 193 | tags |
194 | downloadEnabled: true, | ||
195 | description: videoInfo.description || undefined, | ||
196 | support: undefined, | ||
197 | tags, | ||
198 | privacy: VideoPrivacy.PUBLIC, | ||
199 | fixture: videoPath, | ||
200 | thumbnailfile, | ||
201 | previewfile: thumbnailfile, | ||
202 | originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null | ||
203 | } | 194 | } |
204 | 195 | ||
205 | if (program[ 'channelId' ]) { | 196 | const videoAttributes = await buildVideoAttributesFromCommander(url, program, defaultAttributes) |
206 | Object.assign(videoAttributes, { channelId: program['channelId'] }) | 197 | |
207 | } | 198 | Object.assign(videoAttributes, { |
199 | originallyPublishedAt: originallyPublishedAt ? originallyPublishedAt.toISOString() : null, | ||
200 | thumbnailfile, | ||
201 | previewfile: thumbnailfile, | ||
202 | fixture: videoPath | ||
203 | }) | ||
208 | 204 | ||
209 | console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) | 205 | console.log('\nUploading on PeerTube video "%s".', videoAttributes.name) |
210 | 206 | ||
diff --git a/server/tools/peertube-upload.ts b/server/tools/peertube-upload.ts index 1da52da31..c00205e8f 100644 --- a/server/tools/peertube-upload.ts +++ b/server/tools/peertube-upload.ts | |||
@@ -3,24 +3,18 @@ import { access, constants } from 'fs-extra' | |||
3 | import { isAbsolute } from 'path' | 3 | import { isAbsolute } from 'path' |
4 | import { getClient, login } from '../../shared/extra-utils' | 4 | import { getClient, login } from '../../shared/extra-utils' |
5 | import { uploadVideo } from '../../shared/extra-utils/' | 5 | import { uploadVideo } from '../../shared/extra-utils/' |
6 | import { VideoPrivacy } from '../../shared/models/videos' | 6 | import { buildCommonVideoOptions, buildVideoAttributesFromCommander, getNetrc, getRemoteObjectOrDie, getSettings } from './cli' |
7 | import { getNetrc, getRemoteObjectOrDie, getSettings } from './cli' | ||
8 | 7 | ||
9 | program | 8 | let command = program |
10 | .name('upload') | 9 | .name('upload') |
10 | |||
11 | command = buildCommonVideoOptions(command) | ||
12 | |||
13 | command | ||
14 | |||
11 | .option('-u, --url <url>', 'Server url') | 15 | .option('-u, --url <url>', 'Server url') |
12 | .option('-U, --username <username>', 'Username') | 16 | .option('-U, --username <username>', 'Username') |
13 | .option('-p, --password <token>', 'Password') | 17 | .option('-p, --password <token>', 'Password') |
14 | .option('-n, --video-name <name>', 'Video name') | ||
15 | .option('-P, --privacy <privacy_number>', 'Privacy') | ||
16 | .option('-N, --nsfw', 'Video is Not Safe For Work') | ||
17 | .option('-c, --category <category_number>', 'Category number') | ||
18 | .option('-C, --channel-id <channel_id>', 'Channel ID') | ||
19 | .option('-m, --comments-enabled', 'Enable comments') | ||
20 | .option('-l, --licence <licence_number>', 'Licence number') | ||
21 | .option('-L, --language <language_code>', 'Language ISO 639 code (fr or en...)') | ||
22 | .option('-d, --video-description <description>', 'Video description') | ||
23 | .option('-t, --tags <tags>', 'Video tags', list) | ||
24 | .option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path') | 18 | .option('-b, --thumbnail <thumbnailPath>', 'Thumbnail path') |
25 | .option('-v, --preview <previewPath>', 'Preview path') | 19 | .option('-v, --preview <previewPath>', 'Preview path') |
26 | .option('-f, --file <file>', 'Video absolute file path') | 20 | .option('-f, --file <file>', 'Video absolute file path') |
@@ -30,10 +24,9 @@ Promise.all([ getSettings(), getNetrc() ]) | |||
30 | .then(([ settings, netrc ]) => { | 24 | .then(([ settings, netrc ]) => { |
31 | const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc) | 25 | const { url, username, password } = getRemoteObjectOrDie(program, settings, netrc) |
32 | 26 | ||
33 | if (!program[ 'videoName' ] || !program[ 'file' ] || !program[ 'channelId' ]) { | 27 | if (!program[ 'videoName' ] || !program[ 'file' ]) { |
34 | if (!program[ 'videoName' ]) console.error('--video-name is required.') | 28 | if (!program[ 'videoName' ]) console.error('--video-name is required.') |
35 | if (!program[ 'file' ]) console.error('--file is required.') | 29 | if (!program[ 'file' ]) console.error('--file is required.') |
36 | if (!program[ 'channelId' ]) console.error('--channel-id is required.') | ||
37 | 30 | ||
38 | process.exit(-1) | 31 | process.exit(-1) |
39 | } | 32 | } |
@@ -70,24 +63,17 @@ async function run (url: string, username: string, password: string) { | |||
70 | 63 | ||
71 | console.log('Uploading %s video...', program[ 'videoName' ]) | 64 | console.log('Uploading %s video...', program[ 'videoName' ]) |
72 | 65 | ||
73 | const videoAttributes = { | 66 | const defaultAttributes = { |
74 | name: program[ 'videoName' ], | 67 | tags: command[ 'tags' ], |
75 | category: program[ 'category' ] || undefined, | 68 | description: command[ 'videoDescription' ] |
76 | channelId: program[ 'channelId' ], | 69 | } |
77 | licence: program[ 'licence' ] || undefined, | 70 | const videoAttributes = await buildVideoAttributesFromCommander(url, program, defaultAttributes) |
78 | language: program[ 'language' ] || undefined, | 71 | |
79 | nsfw: program[ 'nsfw' ] !== undefined ? program[ 'nsfw' ] : false, | 72 | Object.assign(videoAttributes, { |
80 | description: program[ 'videoDescription' ] || undefined, | ||
81 | tags: program[ 'tags' ] || [], | ||
82 | commentsEnabled: program[ 'commentsEnabled' ] !== undefined ? program[ 'commentsEnabled' ] : true, | ||
83 | downloadEnabled: program[ 'downloadEnabled' ] !== undefined ? program[ 'downloadEnabled' ] : true, | ||
84 | fixture: program[ 'file' ], | 73 | fixture: program[ 'file' ], |
85 | thumbnailfile: program[ 'thumbnail' ], | 74 | thumbnailfile: program[ 'thumbnail' ], |
86 | previewfile: program[ 'preview' ], | 75 | previewfile: program[ 'preview' ] |
87 | waitTranscoding: true, | 76 | }) |
88 | privacy: program[ 'privacy' ] || VideoPrivacy.PUBLIC, | ||
89 | support: undefined | ||
90 | } | ||
91 | 77 | ||
92 | try { | 78 | try { |
93 | await uploadVideo(url, accessToken, videoAttributes) | 79 | await uploadVideo(url, accessToken, videoAttributes) |
@@ -100,7 +86,3 @@ async function run (url: string, username: string, password: string) { | |||
100 | } | 86 | } |
101 | 87 | ||
102 | // ---------------------------------------------------------------------------- | 88 | // ---------------------------------------------------------------------------- |
103 | |||
104 | function list (val) { | ||
105 | return val.split(',') | ||
106 | } | ||