Merge branch 'release/2.1.0'
This commit is contained in:
commit
16ec5e0833
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -1,5 +1,20 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## v2.1.1
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
* Fix youtube-dl in docker image
|
||||||
|
* Fix playlist creation/update
|
||||||
|
* Fix fetch of instance config in client
|
||||||
|
* Manual approves followers only for the instance (and not accounts/channels)
|
||||||
|
* Fix avatar update
|
||||||
|
* Fix CSP for embeds
|
||||||
|
* Fix scroll of the menu on mobile
|
||||||
|
* Fix CPU usage of PostgreSQL
|
||||||
|
* Fix embed for iOS
|
||||||
|
|
||||||
|
|
||||||
## v2.1.0
|
## v2.1.0
|
||||||
|
|
||||||
**Since v2.0.0**
|
**Since v2.0.0**
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "peertube-client",
|
"name": "peertube-client",
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"author": {
|
"author": {
|
||||||
|
|
|
@ -159,8 +159,11 @@ export class ServerService {
|
||||||
if (!this.configObservable) {
|
if (!this.configObservable) {
|
||||||
this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
|
this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(this.saveConfigLocally),
|
tap(config => this.saveConfigLocally(config)),
|
||||||
tap(() => this.configLoaded = true),
|
tap(config => {
|
||||||
|
this.config = config
|
||||||
|
this.configLoaded = true
|
||||||
|
}),
|
||||||
tap(() => {
|
tap(() => {
|
||||||
if (this.configReset) {
|
if (this.configReset) {
|
||||||
this.configReloaded.next()
|
this.configReloaded.next()
|
||||||
|
|
|
@ -254,6 +254,10 @@ menu {
|
||||||
@media screen and (max-width: $mobile-view) {
|
@media screen and (max-width: $mobile-view) {
|
||||||
.menu-wrapper {
|
.menu-wrapper {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
|
|
||||||
|
menu {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-menu, .footer {
|
.top-menu, .footer {
|
||||||
|
|
|
@ -141,6 +141,8 @@ export class VideoPlaylistService {
|
||||||
return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data)
|
return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(res => {
|
tap(res => {
|
||||||
|
if (!this.myAccountPlaylistCache) return
|
||||||
|
|
||||||
this.myAccountPlaylistCache.total++
|
this.myAccountPlaylistCache.total++
|
||||||
|
|
||||||
this.myAccountPlaylistCache.data.push({
|
this.myAccountPlaylistCache.data.push({
|
||||||
|
@ -161,6 +163,8 @@ export class VideoPlaylistService {
|
||||||
.pipe(
|
.pipe(
|
||||||
map(this.restExtractor.extractDataBool),
|
map(this.restExtractor.extractDataBool),
|
||||||
tap(() => {
|
tap(() => {
|
||||||
|
if (!this.myAccountPlaylistCache) return
|
||||||
|
|
||||||
const playlist = this.myAccountPlaylistCache.data.find(p => p.id === videoPlaylist.id)
|
const playlist = this.myAccountPlaylistCache.data.find(p => p.id === videoPlaylist.id)
|
||||||
playlist.displayName = body.displayName
|
playlist.displayName = body.displayName
|
||||||
|
|
||||||
|
@ -175,6 +179,8 @@ export class VideoPlaylistService {
|
||||||
.pipe(
|
.pipe(
|
||||||
map(this.restExtractor.extractDataBool),
|
map(this.restExtractor.extractDataBool),
|
||||||
tap(() => {
|
tap(() => {
|
||||||
|
if (!this.myAccountPlaylistCache) return
|
||||||
|
|
||||||
this.myAccountPlaylistCache.total--
|
this.myAccountPlaylistCache.total--
|
||||||
this.myAccountPlaylistCache.data = this.myAccountPlaylistCache.data
|
this.myAccountPlaylistCache.data = this.myAccountPlaylistCache.data
|
||||||
.filter(p => p.id !== videoPlaylist.id)
|
.filter(p => p.id !== videoPlaylist.id)
|
||||||
|
|
|
@ -262,6 +262,9 @@ export class PeerTubeEmbed {
|
||||||
|
|
||||||
private async buildDock (videoInfo: VideoDetails, configResponse: Response) {
|
private async buildDock (videoInfo: VideoDetails, configResponse: Response) {
|
||||||
if (this.controls) {
|
if (this.controls) {
|
||||||
|
// On webtorrent fallback, player may have been disposed
|
||||||
|
if (!this.player.player_) return
|
||||||
|
|
||||||
const title = this.title ? videoInfo.name : undefined
|
const title = this.title ? videoInfo.name : undefined
|
||||||
|
|
||||||
const config: ServerConfig = await configResponse.json()
|
const config: ServerConfig = await configResponse.json()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "peertube",
|
"name": "peertube",
|
||||||
"description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.",
|
"description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.",
|
||||||
"version": "2.1.0",
|
"version": "2.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"licence": "AGPL-3.0",
|
"licence": "AGPL-3.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
|
@ -2,10 +2,11 @@ import * as express from 'express'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import { root } from '../helpers/core-utils'
|
import { root } from '../helpers/core-utils'
|
||||||
import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers/constants'
|
import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers/constants'
|
||||||
import { asyncMiddleware } from '../middlewares'
|
import { asyncMiddleware, embedCSP } from '../middlewares'
|
||||||
import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n'
|
import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n'
|
||||||
import { ClientHtml } from '../lib/client-html'
|
import { ClientHtml } from '../lib/client-html'
|
||||||
import { logger } from '../helpers/logger'
|
import { logger } from '../helpers/logger'
|
||||||
|
import { CONFIG } from '@server/initializers/config'
|
||||||
|
|
||||||
const clientsRouter = express.Router()
|
const clientsRouter = express.Router()
|
||||||
|
|
||||||
|
@ -19,8 +20,13 @@ clientsRouter.use('/videos/watch/:id', asyncMiddleware(generateWatchHtmlPage))
|
||||||
clientsRouter.use('/accounts/:nameWithHost', asyncMiddleware(generateAccountHtmlPage))
|
clientsRouter.use('/accounts/:nameWithHost', asyncMiddleware(generateAccountHtmlPage))
|
||||||
clientsRouter.use('/video-channels/:nameWithHost', asyncMiddleware(generateVideoChannelHtmlPage))
|
clientsRouter.use('/video-channels/:nameWithHost', asyncMiddleware(generateVideoChannelHtmlPage))
|
||||||
|
|
||||||
|
const embedCSPMiddleware = CONFIG.CSP.ENABLED
|
||||||
|
? embedCSP
|
||||||
|
: (req: express.Request, res: express.Response, next: express.NextFunction) => next()
|
||||||
|
|
||||||
clientsRouter.use(
|
clientsRouter.use(
|
||||||
'/videos/embed',
|
'/videos/embed',
|
||||||
|
embedCSPMiddleware,
|
||||||
(req: express.Request, res: express.Response) => {
|
(req: express.Request, res: express.Response) => {
|
||||||
res.removeHeader('X-Frame-Options')
|
res.removeHeader('X-Frame-Options')
|
||||||
res.sendFile(embedPath)
|
res.sendFile(embedPath)
|
||||||
|
|
|
@ -176,8 +176,8 @@ async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo
|
||||||
if (!info.name) return actor
|
if (!info.name) return actor
|
||||||
|
|
||||||
if (actor.Avatar) {
|
if (actor.Avatar) {
|
||||||
// Don't update the avatar if the filename did not change
|
// Don't update the avatar if the file URL did not change
|
||||||
if (actor.Avatar.fileUrl === info.fileUrl) return actor
|
if (info.fileUrl && actor.Avatar.fileUrl === info.fileUrl) return actor
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await actor.Avatar.destroy({ transaction: t })
|
await actor.Avatar.destroy({ transaction: t })
|
||||||
|
|
|
@ -59,7 +59,9 @@ async function processFollow (byActor: MActorSignature, targetActorURL: string)
|
||||||
transaction: t
|
transaction: t
|
||||||
})
|
})
|
||||||
|
|
||||||
if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) {
|
// Set the follow as accepted if the remote actor follows a channel or account
|
||||||
|
// Or if the instance automatically accepts followers
|
||||||
|
if (actorFollow.state !== 'accepted' && (isFollowingInstance === false || CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false)) {
|
||||||
actorFollow.state = 'accepted'
|
actorFollow.state = 'accepted'
|
||||||
await actorFollow.save({ transaction: t })
|
await actorFollow.save({ transaction: t })
|
||||||
}
|
}
|
||||||
|
|
|
@ -136,8 +136,7 @@ import {
|
||||||
MVideoThumbnailBlacklist,
|
MVideoThumbnailBlacklist,
|
||||||
MVideoWithAllFiles,
|
MVideoWithAllFiles,
|
||||||
MVideoWithFile,
|
MVideoWithFile,
|
||||||
MVideoWithRights,
|
MVideoWithRights
|
||||||
MStreamingPlaylistFiles
|
|
||||||
} from '../../typings/models'
|
} from '../../typings/models'
|
||||||
import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file'
|
import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file'
|
||||||
import { MThumbnail } from '../../typings/models/video/thumbnail'
|
import { MThumbnail } from '../../typings/models/video/thumbnail'
|
||||||
|
@ -437,42 +436,31 @@ export type AvailableForListIDsOptions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.followerActorId) {
|
if (options.followerActorId) {
|
||||||
let localVideosReq: WhereOptions = {}
|
let localVideosReq = ''
|
||||||
if (options.includeLocalVideos === true) {
|
if (options.includeLocalVideos === true) {
|
||||||
localVideosReq = { remote: false }
|
localVideosReq = ' UNION ALL SELECT "video"."id" FROM "video" WHERE remote IS FALSE'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force actorId to be a number to avoid SQL injections
|
// Force actorId to be a number to avoid SQL injections
|
||||||
const actorIdNumber = parseInt(options.followerActorId.toString(), 10)
|
const actorIdNumber = parseInt(options.followerActorId.toString(), 10)
|
||||||
whereAnd.push({
|
whereAnd.push({
|
||||||
[Op.or]: [
|
|
||||||
{
|
|
||||||
id: {
|
id: {
|
||||||
[Op.in]: Sequelize.literal(
|
[Op.in]: Sequelize.literal(
|
||||||
'(' +
|
'(' +
|
||||||
'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
|
'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
|
||||||
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
|
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
|
||||||
'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
|
'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
|
||||||
')'
|
' UNION ALL ' +
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: {
|
|
||||||
[ Op.in ]: Sequelize.literal(
|
|
||||||
'(' +
|
|
||||||
'SELECT "video"."id" AS "id" FROM "video" ' +
|
'SELECT "video"."id" AS "id" FROM "video" ' +
|
||||||
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
|
||||||
'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
|
'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
|
||||||
'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
|
'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
|
||||||
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
|
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
|
||||||
'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
|
'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
|
||||||
|
localVideosReq +
|
||||||
')'
|
')'
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
|
||||||
localVideosReq
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
info:
|
info:
|
||||||
title: PeerTube
|
title: PeerTube
|
||||||
version: 2.1.0
|
version: 2.1.1
|
||||||
contact:
|
contact:
|
||||||
name: PeerTube Community
|
name: PeerTube Community
|
||||||
url: 'https://joinpeertube.org'
|
url: 'https://joinpeertube.org'
|
||||||
|
|
|
@ -7,7 +7,7 @@ ARG NPM_RUN_BUILD_OPTS
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
RUN apt update \
|
RUN apt update \
|
||||||
&& apt install -y --no-install-recommends openssl ffmpeg gnupg gosu \
|
&& apt install -y --no-install-recommends openssl ffmpeg python ca-certificates gnupg gosu \
|
||||||
&& gosu nobody true \
|
&& gosu nobody true \
|
||||||
&& rm /var/lib/apt/lists/* -fR
|
&& rm /var/lib/apt/lists/* -fR
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue