Merge branch 'release/5.0.0' into develop
This commit is contained in:
commit
93293ca788
|
@ -16,11 +16,11 @@
|
||||||
* 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`
|
* 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`
|
||||||
* Docker installation: `cd /var/www/peertube-docker && docker-compose exec -u peertube peertube node dist/scripts/migrations/peertube-5.0.js`
|
* Docker installation: `cd /var/www/peertube-docker && docker-compose exec -u peertube peertube node dist/scripts/migrations/peertube-5.0.js`
|
||||||
* Configuration changes (`config/production.yaml`):
|
* Configuration changes (`config/production.yaml`):
|
||||||
* There is a new `secrets.peertube` configuration. You must fill it before running PeerTube v5
|
* 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
|
||||||
* `object_storage.upload_acl` is now a parent key that you must update
|
* `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
|
||||||
* You must update your nginx configuration:
|
* You must update your nginx configuration:
|
||||||
* We introduced a new `location` for plugin websocket routes
|
* We introduced a new `location` for plugin websocket routes: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/support/nginx/peertube#L135
|
||||||
* We introduced a new `location` for private videos files
|
* We introduced a new `location` for private videos files: https://github.com/Chocobozzz/PeerTube/blob/v5.0.0/support/nginx/peertube#L217
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
if (!videoId) return
|
if (!videoId) return
|
||||||
|
|
||||||
return this.loadVideoAndBuildPlayer({ uuid: videoId, forceAutoplay: false })
|
return this.loadVideoAndBuildPlayer({ uuid: videoId, autoplayFromPreviousVideo: false, forceAutoplay: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
private async initPlaylist () {
|
private async initPlaylist () {
|
||||||
|
@ -147,7 +147,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
this.playlistTracker.setCurrentElement(next)
|
this.playlistTracker.setCurrentElement(next)
|
||||||
|
|
||||||
return this.loadVideoAndBuildPlayer({ uuid: next.video.uuid, forceAutoplay: false })
|
return this.loadVideoAndBuildPlayer({ uuid: next.video.uuid, autoplayFromPreviousVideo: true, forceAutoplay: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
async playPreviousPlaylistVideo () {
|
async playPreviousPlaylistVideo () {
|
||||||
|
@ -159,7 +159,7 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
this.playlistTracker.setCurrentElement(previous)
|
this.playlistTracker.setCurrentElement(previous)
|
||||||
|
|
||||||
await this.loadVideoAndBuildPlayer({ uuid: previous.video.uuid, forceAutoplay: false })
|
await this.loadVideoAndBuildPlayer({ uuid: previous.video.uuid, autoplayFromPreviousVideo: true, forceAutoplay: false })
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPlaylistPosition () {
|
getCurrentPlaylistPosition () {
|
||||||
|
@ -170,14 +170,15 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
private async loadVideoAndBuildPlayer (options: {
|
private async loadVideoAndBuildPlayer (options: {
|
||||||
uuid: string
|
uuid: string
|
||||||
|
autoplayFromPreviousVideo: boolean
|
||||||
forceAutoplay: boolean
|
forceAutoplay: boolean
|
||||||
}) {
|
}) {
|
||||||
const { uuid, forceAutoplay } = options
|
const { uuid, autoplayFromPreviousVideo, forceAutoplay } = options
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { videoResponse, captionsPromise } = await this.videoFetcher.loadVideo(uuid)
|
const { videoResponse, captionsPromise } = await this.videoFetcher.loadVideo(uuid)
|
||||||
|
|
||||||
return this.buildVideoPlayer({ videoResponse, captionsPromise, forceAutoplay })
|
return this.buildVideoPlayer({ videoResponse, captionsPromise, autoplayFromPreviousVideo, forceAutoplay })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.playerHTML.displayError(err.message, await this.translationsPromise)
|
this.playerHTML.displayError(err.message, await this.translationsPromise)
|
||||||
}
|
}
|
||||||
|
@ -186,17 +187,18 @@ export class PeerTubeEmbed {
|
||||||
private async buildVideoPlayer (options: {
|
private async buildVideoPlayer (options: {
|
||||||
videoResponse: Response
|
videoResponse: Response
|
||||||
captionsPromise: Promise<Response>
|
captionsPromise: Promise<Response>
|
||||||
|
autoplayFromPreviousVideo: boolean
|
||||||
forceAutoplay: boolean
|
forceAutoplay: boolean
|
||||||
}) {
|
}) {
|
||||||
const { videoResponse, captionsPromise, forceAutoplay } = options
|
const { videoResponse, captionsPromise, autoplayFromPreviousVideo, forceAutoplay } = options
|
||||||
|
|
||||||
const alreadyHadPlayer = this.resetPlayerElement()
|
this.resetPlayerElement()
|
||||||
|
|
||||||
const videoInfoPromise = videoResponse.json()
|
const videoInfoPromise = videoResponse.json()
|
||||||
.then(async (videoInfo: VideoDetails) => {
|
.then(async (videoInfo: VideoDetails) => {
|
||||||
this.playerManagerOptions.loadParams(this.config, videoInfo)
|
this.playerManagerOptions.loadParams(this.config, videoInfo)
|
||||||
|
|
||||||
if (!alreadyHadPlayer && !this.playerManagerOptions.hasAutoplay()) {
|
if (!autoplayFromPreviousVideo && !this.playerManagerOptions.hasAutoplay()) {
|
||||||
this.playerHTML.buildPlaceholder(videoInfo)
|
this.playerHTML.buildPlaceholder(videoInfo)
|
||||||
}
|
}
|
||||||
const live = videoInfo.isLive
|
const live = videoInfo.isLive
|
||||||
|
@ -224,14 +226,14 @@ export class PeerTubeEmbed {
|
||||||
const playerOptions = await this.playerManagerOptions.getPlayerOptions({
|
const playerOptions = await this.playerManagerOptions.getPlayerOptions({
|
||||||
video,
|
video,
|
||||||
captionsResponse,
|
captionsResponse,
|
||||||
alreadyHadPlayer,
|
autoplayFromPreviousVideo,
|
||||||
translations,
|
translations,
|
||||||
serverConfig: this.config,
|
serverConfig: this.config,
|
||||||
|
|
||||||
authorizationHeader: () => this.http.getHeaderTokenValue(),
|
authorizationHeader: () => this.http.getHeaderTokenValue(),
|
||||||
videoFileToken: () => videoFileToken,
|
videoFileToken: () => videoFileToken,
|
||||||
|
|
||||||
onVideoUpdate: (uuid: string) => this.loadVideoAndBuildPlayer({ uuid, forceAutoplay: false }),
|
onVideoUpdate: (uuid: string) => this.loadVideoAndBuildPlayer({ uuid, autoplayFromPreviousVideo: true, forceAutoplay: false }),
|
||||||
|
|
||||||
playlistTracker: this.playlistTracker,
|
playlistTracker: this.playlistTracker,
|
||||||
playNextPlaylistVideo: () => this.playNextPlaylistVideo(),
|
playNextPlaylistVideo: () => this.playNextPlaylistVideo(),
|
||||||
|
@ -277,7 +279,7 @@ export class PeerTubeEmbed {
|
||||||
video,
|
video,
|
||||||
onPublishedVideo: () => {
|
onPublishedVideo: () => {
|
||||||
this.liveManager.stopListeningForChanges(video)
|
this.liveManager.stopListeningForChanges(video)
|
||||||
this.loadVideoAndBuildPlayer({ uuid: video.uuid, forceAutoplay: true })
|
this.loadVideoAndBuildPlayer({ uuid: video.uuid, autoplayFromPreviousVideo: false, forceAutoplay: true })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -294,12 +296,9 @@ export class PeerTubeEmbed {
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetPlayerElement () {
|
private resetPlayerElement () {
|
||||||
let alreadyHadPlayer = false
|
|
||||||
|
|
||||||
if (this.player) {
|
if (this.player) {
|
||||||
this.player.dispose()
|
this.player.dispose()
|
||||||
this.player = undefined
|
this.player = undefined
|
||||||
alreadyHadPlayer = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const playerElement = document.createElement('video')
|
const playerElement = document.createElement('video')
|
||||||
|
@ -308,8 +307,6 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
this.playerHTML.setPlayerElement(playerElement)
|
this.playerHTML.setPlayerElement(playerElement)
|
||||||
this.playerHTML.addPlayerElementToDOM()
|
this.playerHTML.addPlayerElementToDOM()
|
||||||
|
|
||||||
return alreadyHadPlayer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async buildPlayerPlaylistUpnext () {
|
private async buildPlayerPlaylistUpnext () {
|
||||||
|
|
|
@ -162,7 +162,7 @@ export class PlayerManagerOptions {
|
||||||
|
|
||||||
serverConfig: HTMLServerConfig
|
serverConfig: HTMLServerConfig
|
||||||
|
|
||||||
alreadyHadPlayer: boolean
|
autoplayFromPreviousVideo: boolean
|
||||||
|
|
||||||
translations: Translations
|
translations: Translations
|
||||||
|
|
||||||
|
@ -174,7 +174,7 @@ export class PlayerManagerOptions {
|
||||||
const {
|
const {
|
||||||
video,
|
video,
|
||||||
captionsResponse,
|
captionsResponse,
|
||||||
alreadyHadPlayer,
|
autoplayFromPreviousVideo,
|
||||||
videoFileToken,
|
videoFileToken,
|
||||||
translations,
|
translations,
|
||||||
forceAutoplay,
|
forceAutoplay,
|
||||||
|
@ -189,7 +189,7 @@ export class PlayerManagerOptions {
|
||||||
const playerOptions: PeertubePlayerManagerOptions = {
|
const playerOptions: PeertubePlayerManagerOptions = {
|
||||||
common: {
|
common: {
|
||||||
// Autoplay in playlist mode
|
// Autoplay in playlist mode
|
||||||
autoplay: alreadyHadPlayer ? true : this.autoplay,
|
autoplay: autoplayFromPreviousVideo ? true : this.autoplay,
|
||||||
forceAutoplay,
|
forceAutoplay,
|
||||||
|
|
||||||
controls: this.controls,
|
controls: this.controls,
|
||||||
|
|
|
@ -15,6 +15,7 @@ import {
|
||||||
} from '@server/middlewares'
|
} from '@server/middlewares'
|
||||||
import { HttpStatusCode } from '@shared/models'
|
import { HttpStatusCode } from '@shared/models'
|
||||||
import { buildReinjectVideoFileTokenQuery, doReinjectVideoFileToken } from './shared/m3u8-playlist'
|
import { buildReinjectVideoFileTokenQuery, doReinjectVideoFileToken } from './shared/m3u8-playlist'
|
||||||
|
import { GetObjectCommandOutput } from '@aws-sdk/client-s3'
|
||||||
|
|
||||||
const objectStorageProxyRouter = express.Router()
|
const objectStorageProxyRouter = express.Router()
|
||||||
|
|
||||||
|
@ -46,11 +47,13 @@ async function proxifyWebTorrent (req: express.Request, res: express.Response) {
|
||||||
logger.debug('Proxifying WebTorrent file %s from object storage.', filename)
|
logger.debug('Proxifying WebTorrent file %s from object storage.', filename)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stream = await getWebTorrentFileReadStream({
|
const { response: s3Response, stream } = await getWebTorrentFileReadStream({
|
||||||
filename,
|
filename,
|
||||||
rangeHeader: req.header('range')
|
rangeHeader: req.header('range')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setS3Headers(res, s3Response)
|
||||||
|
|
||||||
return stream.pipe(res)
|
return stream.pipe(res)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return handleObjectStorageFailure(res, err)
|
return handleObjectStorageFailure(res, err)
|
||||||
|
@ -65,12 +68,14 @@ async function proxifyHLS (req: express.Request, res: express.Response) {
|
||||||
logger.debug('Proxifying HLS file %s from object storage.', filename)
|
logger.debug('Proxifying HLS file %s from object storage.', filename)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stream = await getHLSFileReadStream({
|
const { response: s3Response, stream } = await getHLSFileReadStream({
|
||||||
playlist: playlist.withVideo(video),
|
playlist: playlist.withVideo(video),
|
||||||
filename,
|
filename,
|
||||||
rangeHeader: req.header('range')
|
rangeHeader: req.header('range')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setS3Headers(res, s3Response)
|
||||||
|
|
||||||
const streamReplacer = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req)
|
const streamReplacer = filename.endsWith('.m3u8') && doReinjectVideoFileToken(req)
|
||||||
? new StreamReplacer(line => injectQueryToPlaylistUrls(line, buildReinjectVideoFileTokenQuery(req)))
|
? new StreamReplacer(line => injectQueryToPlaylistUrls(line, buildReinjectVideoFileTokenQuery(req)))
|
||||||
: new PassThrough()
|
: new PassThrough()
|
||||||
|
@ -102,3 +107,9 @@ function handleObjectStorageFailure (res: express.Response, err: Error) {
|
||||||
type: err.name
|
type: err.name
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setS3Headers (res: express.Response, s3Response: GetObjectCommandOutput) {
|
||||||
|
if (s3Response.$metadata.httpStatusCode === HttpStatusCode.PARTIAL_CONTENT_206) {
|
||||||
|
res.status(HttpStatusCode.PARTIAL_CONTENT_206)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -187,7 +187,10 @@ async function createObjectReadStream (options: {
|
||||||
|
|
||||||
const response = await getClient().send(command)
|
const response = await getClient().send(command)
|
||||||
|
|
||||||
return response.Body as Readable
|
return {
|
||||||
|
response,
|
||||||
|
stream: response.Body as Readable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
@ -8128,17 +8128,13 @@ components:
|
||||||
NotificationSettingValue:
|
NotificationSettingValue:
|
||||||
type: integer
|
type: integer
|
||||||
description: >
|
description: >
|
||||||
Notification type
|
Notification type. One of the following values, or a sum of multiple values:
|
||||||
|
|
||||||
- `0` NONE
|
- `0` NONE
|
||||||
|
|
||||||
- `1` WEB
|
- `1` WEB
|
||||||
|
|
||||||
- `2` EMAIL
|
- `2` EMAIL
|
||||||
enum:
|
|
||||||
- 0
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
Notification:
|
Notification:
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user