aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--client/src/standalone/videos/embed.ts29
-rw-r--r--client/src/standalone/videos/shared/player-manager-options.ts6
-rw-r--r--server/controllers/object-storage-proxy.ts15
-rw-r--r--server/lib/object-storage/shared/object-storage-helpers.ts5
-rw-r--r--support/doc/api/openapi.yaml6
6 files changed, 38 insertions, 31 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 182beb67b..36506e20e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,11 +16,11 @@
16 * Classic installation: `cd /var/www/peertube/peertube-latest && sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production node dist/scripts/migrations/peertube-5.0.js` 16 * Classic installation: `cd /var/www/peertube/peertube-latest && sudo -u peertube NODE_CONFIG_DIR=/var/www/peertube/config NODE_ENV=production node dist/scripts/migrations/peertube-5.0.js`
17 * Docker installation: `cd /var/www/peertube-docker && docker-compose exec -u peertube peertube node dist/scripts/migrations/peertube-5.0.js` 17 * Docker installation: `cd /var/www/peertube-docker && docker-compose exec -u peertube peertube node dist/scripts/migrations/peertube-5.0.js`
18 * Configuration changes (`config/production.yaml`): 18 * Configuration changes (`config/production.yaml`):
19 * There is a new `secrets.peertube` configuration. You must fill it before running PeerTube v5 19 * There is a new `secrets.peertube` configuration. You must fill it before running PeerTube v5: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/config/production.yaml.example#L14
20 * `object_storage.upload_acl` is now a parent key that you must update 20 * `object_storage.upload_acl` is now a parent key that you must update: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/config/production.yaml.example#L153
21 * You must update your nginx configuration: 21 * You must update your nginx configuration:
22 * We introduced a new `location` for plugin websocket routes 22 * We introduced a new `location` for plugin websocket routes: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/support/nginx/peertube#L135
23 * We introduced a new `location` for private videos files 23 * We introduced a new `location` for private videos files: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/support/nginx/peertube#L217
24 24
25### Documentation 25### Documentation
26 26
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index 5bb3b43c2..d268f4762 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -90,7 +90,7 @@ export class PeerTubeEmbed {
90 90
91 if (!videoId) return 91 if (!videoId) return
92 92
93 return this.loadVideoAndBuildPlayer({ uuid: videoId, forceAutoplay: false }) 93 return this.loadVideoAndBuildPlayer({ uuid: videoId, autoplayFromPreviousVideo: false, forceAutoplay: false })
94 } 94 }
95 95
96 private async initPlaylist () { 96 private async initPlaylist () {
@@ -147,7 +147,7 @@ export class PeerTubeEmbed {
147 147
148 this.playlistTracker.setCurrentElement(next) 148 this.playlistTracker.setCurrentElement(next)
149 149
150 return this.loadVideoAndBuildPlayer({ uuid: next.video.uuid, forceAutoplay: false }) 150 return this.loadVideoAndBuildPlayer({ uuid: next.video.uuid, autoplayFromPreviousVideo: true, forceAutoplay: false })
151 } 151 }
152 152
153 async playPreviousPlaylistVideo () { 153 async playPreviousPlaylistVideo () {
@@ -159,7 +159,7 @@ export class PeerTubeEmbed {
159 159
160 this.playlistTracker.setCurrentElement(previous) 160 this.playlistTracker.setCurrentElement(previous)
161 161
162 await this.loadVideoAndBuildPlayer({ uuid: previous.video.uuid, forceAutoplay: false }) 162 await this.loadVideoAndBuildPlayer({ uuid: previous.video.uuid, autoplayFromPreviousVideo: true, forceAutoplay: false })
163 } 163 }
164 164
165 getCurrentPlaylistPosition () { 165 getCurrentPlaylistPosition () {
@@ -170,14 +170,15 @@ export class PeerTubeEmbed {
170 170
171 private async loadVideoAndBuildPlayer (options: { 171 private async loadVideoAndBuildPlayer (options: {
172 uuid: string 172 uuid: string
173 autoplayFromPreviousVideo: boolean
173 forceAutoplay: boolean 174 forceAutoplay: boolean
174 }) { 175 }) {
175 const { uuid, forceAutoplay } = options 176 const { uuid, autoplayFromPreviousVideo, forceAutoplay } = options
176 177
177 try { 178 try {
178 const { videoResponse, captionsPromise } = await this.videoFetcher.loadVideo(uuid) 179 const { videoResponse, captionsPromise } = await this.videoFetcher.loadVideo(uuid)
179 180
180 return this.buildVideoPlayer({ videoResponse, captionsPromise, forceAutoplay }) 181 return this.buildVideoPlayer({ videoResponse, captionsPromise, autoplayFromPreviousVideo, forceAutoplay })
181 } catch (err) { 182 } catch (err) {
182 this.playerHTML.displayError(err.message, await this.translationsPromise) 183 this.playerHTML.displayError(err.message, await this.translationsPromise)
183 } 184 }
@@ -186,17 +187,18 @@ export class PeerTubeEmbed {
186 private async buildVideoPlayer (options: { 187 private async buildVideoPlayer (options: {
187 videoResponse: Response 188 videoResponse: Response
188 captionsPromise: Promise<Response> 189 captionsPromise: Promise<Response>
190 autoplayFromPreviousVideo: boolean
189 forceAutoplay: boolean 191 forceAutoplay: boolean
190 }) { 192 }) {
191 const { videoResponse, captionsPromise, forceAutoplay } = options 193 const { videoResponse, captionsPromise, autoplayFromPreviousVideo, forceAutoplay } = options
192 194
193 const alreadyHadPlayer = this.resetPlayerElement() 195 this.resetPlayerElement()
194 196
195 const videoInfoPromise = videoResponse.json() 197 const videoInfoPromise = videoResponse.json()
196 .then(async (videoInfo: VideoDetails) => { 198 .then(async (videoInfo: VideoDetails) => {
197 this.playerManagerOptions.loadParams(this.config, videoInfo) 199 this.playerManagerOptions.loadParams(this.config, videoInfo)
198 200
199 if (!alreadyHadPlayer && !this.playerManagerOptions.hasAutoplay()) { 201 if (!autoplayFromPreviousVideo && !this.playerManagerOptions.hasAutoplay()) {
200 this.playerHTML.buildPlaceholder(videoInfo) 202 this.playerHTML.buildPlaceholder(videoInfo)
201 } 203 }
202 const live = videoInfo.isLive 204 const live = videoInfo.isLive
@@ -224,14 +226,14 @@ export class PeerTubeEmbed {
224 const playerOptions = await this.playerManagerOptions.getPlayerOptions({ 226 const playerOptions = await this.playerManagerOptions.getPlayerOptions({
225 video, 227 video,
226 captionsResponse, 228 captionsResponse,
227 alreadyHadPlayer, 229 autoplayFromPreviousVideo,
228 translations, 230 translations,
229 serverConfig: this.config, 231 serverConfig: this.config,
230 232
231 authorizationHeader: () => this.http.getHeaderTokenValue(), 233 authorizationHeader: () => this.http.getHeaderTokenValue(),
232 videoFileToken: () => videoFileToken, 234 videoFileToken: () => videoFileToken,
233 235
234 onVideoUpdate: (uuid: string) => this.loadVideoAndBuildPlayer({ uuid, forceAutoplay: false }), 236 onVideoUpdate: (uuid: string) => this.loadVideoAndBuildPlayer({ uuid, autoplayFromPreviousVideo: true, forceAutoplay: false }),
235 237
236 playlistTracker: this.playlistTracker, 238 playlistTracker: this.playlistTracker,
237 playNextPlaylistVideo: () => this.playNextPlaylistVideo(), 239 playNextPlaylistVideo: () => this.playNextPlaylistVideo(),
@@ -277,7 +279,7 @@ export class PeerTubeEmbed {
277 video, 279 video,
278 onPublishedVideo: () => { 280 onPublishedVideo: () => {
279 this.liveManager.stopListeningForChanges(video) 281 this.liveManager.stopListeningForChanges(video)
280 this.loadVideoAndBuildPlayer({ uuid: video.uuid, forceAutoplay: true }) 282 this.loadVideoAndBuildPlayer({ uuid: video.uuid, autoplayFromPreviousVideo: false, forceAutoplay: true })
281 } 283 }
282 }) 284 })
283 285
@@ -294,12 +296,9 @@ export class PeerTubeEmbed {
294 } 296 }
295 297
296 private resetPlayerElement () { 298 private resetPlayerElement () {
297 let alreadyHadPlayer = false
298
299 if (this.player) { 299 if (this.player) {
300 this.player.dispose() 300 this.player.dispose()
301 this.player = undefined 301 this.player = undefined
302 alreadyHadPlayer = true
303 } 302 }
304 303
305 const playerElement = document.createElement('video') 304 const playerElement = document.createElement('video')
@@ -308,8 +307,6 @@ export class PeerTubeEmbed {
308 307
309 this.playerHTML.setPlayerElement(playerElement) 308 this.playerHTML.setPlayerElement(playerElement)
310 this.playerHTML.addPlayerElementToDOM() 309 this.playerHTML.addPlayerElementToDOM()
311
312 return alreadyHadPlayer
313 } 310 }
314 311
315 private async buildPlayerPlaylistUpnext () { 312 private async buildPlayerPlaylistUpnext () {
diff --git a/client/src/standalone/videos/shared/player-manager-options.ts b/client/src/standalone/videos/shared/player-manager-options.ts
index 9ec012369..b0bdb2dd9 100644
--- a/client/src/standalone/videos/shared/player-manager-options.ts
+++ b/client/src/standalone/videos/shared/player-manager-options.ts
@@ -162,7 +162,7 @@ export class PlayerManagerOptions {
162 162
163 serverConfig: HTMLServerConfig 163 serverConfig: HTMLServerConfig
164 164
165 alreadyHadPlayer: boolean 165 autoplayFromPreviousVideo: boolean
166 166
167 translations: Translations 167 translations: Translations
168 168
@@ -174,7 +174,7 @@ export class PlayerManagerOptions {
174 const { 174 const {
175 video, 175 video,
176 captionsResponse, 176 captionsResponse,
177 alreadyHadPlayer, 177 autoplayFromPreviousVideo,
178 videoFileToken, 178 videoFileToken,
179 translations, 179 translations,
180 forceAutoplay, 180 forceAutoplay,
@@ -189,7 +189,7 @@ export class PlayerManagerOptions {
189 const playerOptions: PeertubePlayerManagerOptions = { 189 const playerOptions: PeertubePlayerManagerOptions = {
190 common: { 190 common: {
191 // Autoplay in playlist mode 191 // Autoplay in playlist mode
192 autoplay: alreadyHadPlayer ? true : this.autoplay, 192 autoplay: autoplayFromPreviousVideo ? true : this.autoplay,
193 forceAutoplay, 193 forceAutoplay,
194 194
195 controls: this.controls, 195 controls: this.controls,
diff --git a/server/controllers/object-storage-proxy.ts b/server/controllers/object-storage-proxy.ts
index aa853a383..32b8d21da 100644
--- a/server/controllers/object-storage-proxy.ts
+++ b/server/controllers/object-storage-proxy.ts
@@ -15,6 +15,7 @@ import {
15} from '@server/middlewares' 15} from '@server/middlewares'
16import { HttpStatusCode } from '@shared/models' 16import { HttpStatusCode } from '@shared/models'
17import { buildReinjectVideoFileTokenQuery, doReinjectVideoFileToken } from './shared/m3u8-playlist' 17import { buildReinjectVideoFileTokenQuery, doReinjectVideoFileToken } from './shared/m3u8-playlist'
18import { GetObjectCommandOutput } from '@aws-sdk/client-s3'
18 19
19const objectStorageProxyRouter = express.Router() 20const objectStorageProxyRouter = express.Router()
20 21
@@ -46,11 +47,13 @@ async function proxifyWebTorrent (req: express.Request, res: express.Response) {
46 logger.debug('Proxifying WebTorrent file %s from object storage.', filename) 47 logger.debug('Proxifying WebTorrent file %s from object storage.', filename)
47 48
48 try { 49 try {
49 const stream = await getWebTorrentFileReadStream({ 50 const { response: s3Response, stream } = await getWebTorrentFileReadStream({
50 filename, 51 filename,
51 rangeHeader: req.header('range') 52 rangeHeader: req.header('range')
52 }) 53 })
53 54
55 setS3Headers(res, s3Response)
56
54 return stream.pipe(res) 57 return stream.pipe(res)
55 } catch (err) { 58 } catch (err) {
56 return handleObjectStorageFailure(res, err) 59 return handleObjectStorageFailure(res, err)
@@ -65,12 +68,14 @@ async function proxifyHLS (req: express.Request, res: express.Response) {
65 logger.debug('Proxifying HLS file %s from object storage.', filename) 68 logger.debug('Proxifying HLS file %s from object storage.', filename)
66 69
67 try { 70 try {
68 const stream = await getHLSFileReadStream({ 71 const { response: s3Response, stream } = await getHLSFileReadStream({
69 playlist: playlist.withVideo(video), 72 playlist: playlist.withVideo(video),
70 filename, 73 filename,
71 rangeHeader: req.header('range') 74 rangeHeader: req.header('range')
72 }) 75 })
73 76
77 setS3Headers(res, s3Response)
78
74 const streamReplacer = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req) 79 const streamReplacer = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req)
75 ? new StreamReplacer(line => injectQueryToPlaylistUrls(line, buildReinjectVideoFileTokenQuery(req))) 80 ? new StreamReplacer(line => injectQueryToPlaylistUrls(line, buildReinjectVideoFileTokenQuery(req)))
76 : new PassThrough() 81 : new PassThrough()
@@ -102,3 +107,9 @@ function handleObjectStorageFailure (res: express.Response, err: Error) {
102 type: err.name 107 type: err.name
103 }) 108 })
104} 109}
110
111function setS3Headers (res: express.Response, s3Response: GetObjectCommandOutput) {
112 if (s3Response.$metadata.httpStatusCode === HttpStatusCode.PARTIAL_CONTENT_206) {
113 res.status(HttpStatusCode.PARTIAL_CONTENT_206)
114 }
115}
diff --git a/server/lib/object-storage/shared/object-storage-helpers.ts b/server/lib/object-storage/shared/object-storage-helpers.ts
index 3046d76bc..8dff08ab4 100644
--- a/server/lib/object-storage/shared/object-storage-helpers.ts
+++ b/server/lib/object-storage/shared/object-storage-helpers.ts
@@ -187,7 +187,10 @@ async function createObjectReadStream (options: {
187 187
188 const response = await getClient().send(command) 188 const response = await getClient().send(command)
189 189
190 return response.Body as Readable 190 return {
191 response,
192 stream: response.Body as Readable
193 }
191} 194}
192 195
193// --------------------------------------------------------------------------- 196// ---------------------------------------------------------------------------
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml
index c2f9d424e..bfa7235a2 100644
--- a/support/doc/api/openapi.yaml
+++ b/support/doc/api/openapi.yaml
@@ -8128,17 +8128,13 @@ components:
8128 NotificationSettingValue: 8128 NotificationSettingValue:
8129 type: integer 8129 type: integer
8130 description: > 8130 description: >
8131 Notification type 8131 Notification type. One of the following values, or a sum of multiple values:
8132 8132
8133 - `0` NONE 8133 - `0` NONE
8134 8134
8135 - `1` WEB 8135 - `1` WEB
8136 8136
8137 - `2` EMAIL 8137 - `2` EMAIL
8138 enum:
8139 - 0
8140 - 1
8141 - 2
8142 Notification: 8138 Notification:
8143 properties: 8139 properties:
8144 id: 8140 id: