aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md15
-rw-r--r--client/package.json2
-rw-r--r--client/src/app/core/server/server.service.ts7
-rw-r--r--client/src/app/menu/menu.component.scss4
-rw-r--r--client/src/app/shared/video-playlist/video-playlist.service.ts6
-rw-r--r--client/src/standalone/videos/embed.ts3
-rw-r--r--package.json2
-rw-r--r--server/controllers/client.ts8
-rw-r--r--server/lib/activitypub/actor.ts4
-rw-r--r--server/lib/activitypub/process/process-follow.ts4
-rw-r--r--server/models/video/video.ts52
-rw-r--r--support/doc/api/openapi.yaml2
-rw-r--r--support/docker/production/Dockerfile.buster2
13 files changed, 69 insertions, 42 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3149476bb..4887614a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,20 @@
1# Changelog 1# Changelog
2 2
3## v2.1.1
4
5### Bug fixes
6
7 * Fix youtube-dl in docker image
8 * Fix playlist creation/update
9 * Fix fetch of instance config in client
10 * Manual approves followers only for the instance (and not accounts/channels)
11 * Fix avatar update
12 * Fix CSP for embeds
13 * Fix scroll of the menu on mobile
14 * Fix CPU usage of PostgreSQL
15 * Fix embed for iOS
16
17
3## v2.1.0 18## v2.1.0
4 19
5**Since v2.0.0** 20**Since v2.0.0**
diff --git a/client/package.json b/client/package.json
index b9ddf7042..024e0b1d9 100644
--- a/client/package.json
+++ b/client/package.json
@@ -1,6 +1,6 @@
1{ 1{
2 "name": "peertube-client", 2 "name": "peertube-client",
3 "version": "2.1.0", 3 "version": "2.1.1",
4 "private": true, 4 "private": true,
5 "license": "AGPL-3.0", 5 "license": "AGPL-3.0",
6 "author": { 6 "author": {
diff --git a/client/src/app/core/server/server.service.ts b/client/src/app/core/server/server.service.ts
index cdcbcb528..3997ce6db 100644
--- a/client/src/app/core/server/server.service.ts
+++ b/client/src/app/core/server/server.service.ts
@@ -159,8 +159,11 @@ export class ServerService {
159 if (!this.configObservable) { 159 if (!this.configObservable) {
160 this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL) 160 this.configObservable = this.http.get<ServerConfig>(ServerService.BASE_CONFIG_URL)
161 .pipe( 161 .pipe(
162 tap(this.saveConfigLocally), 162 tap(config => this.saveConfigLocally(config)),
163 tap(() => this.configLoaded = true), 163 tap(config => {
164 this.config = config
165 this.configLoaded = true
166 }),
164 tap(() => { 167 tap(() => {
165 if (this.configReset) { 168 if (this.configReset) {
166 this.configReloaded.next() 169 this.configReloaded.next()
diff --git a/client/src/app/menu/menu.component.scss b/client/src/app/menu/menu.component.scss
index 2963d4d19..b05173751 100644
--- a/client/src/app/menu/menu.component.scss
+++ b/client/src/app/menu/menu.component.scss
@@ -254,6 +254,10 @@ menu {
254@media screen and (max-width: $mobile-view) { 254@media screen and (max-width: $mobile-view) {
255 .menu-wrapper { 255 .menu-wrapper {
256 width: 100% !important; 256 width: 100% !important;
257
258 menu {
259 overflow-y: auto;
260 }
257 } 261 }
258 262
259 .top-menu, .footer { 263 .top-menu, .footer {
diff --git a/client/src/app/shared/video-playlist/video-playlist.service.ts b/client/src/app/shared/video-playlist/video-playlist.service.ts
index bae6f9e04..38d915c6b 100644
--- a/client/src/app/shared/video-playlist/video-playlist.service.ts
+++ b/client/src/app/shared/video-playlist/video-playlist.service.ts
@@ -141,6 +141,8 @@ export class VideoPlaylistService {
141 return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data) 141 return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data)
142 .pipe( 142 .pipe(
143 tap(res => { 143 tap(res => {
144 if (!this.myAccountPlaylistCache) return
145
144 this.myAccountPlaylistCache.total++ 146 this.myAccountPlaylistCache.total++
145 147
146 this.myAccountPlaylistCache.data.push({ 148 this.myAccountPlaylistCache.data.push({
@@ -161,6 +163,8 @@ export class VideoPlaylistService {
161 .pipe( 163 .pipe(
162 map(this.restExtractor.extractDataBool), 164 map(this.restExtractor.extractDataBool),
163 tap(() => { 165 tap(() => {
166 if (!this.myAccountPlaylistCache) return
167
164 const playlist = this.myAccountPlaylistCache.data.find(p => p.id === videoPlaylist.id) 168 const playlist = this.myAccountPlaylistCache.data.find(p => p.id === videoPlaylist.id)
165 playlist.displayName = body.displayName 169 playlist.displayName = body.displayName
166 170
@@ -175,6 +179,8 @@ export class VideoPlaylistService {
175 .pipe( 179 .pipe(
176 map(this.restExtractor.extractDataBool), 180 map(this.restExtractor.extractDataBool),
177 tap(() => { 181 tap(() => {
182 if (!this.myAccountPlaylistCache) return
183
178 this.myAccountPlaylistCache.total-- 184 this.myAccountPlaylistCache.total--
179 this.myAccountPlaylistCache.data = this.myAccountPlaylistCache.data 185 this.myAccountPlaylistCache.data = this.myAccountPlaylistCache.data
180 .filter(p => p.id !== videoPlaylist.id) 186 .filter(p => p.id !== videoPlaylist.id)
diff --git a/client/src/standalone/videos/embed.ts b/client/src/standalone/videos/embed.ts
index c91ae08b9..5213443fc 100644
--- a/client/src/standalone/videos/embed.ts
+++ b/client/src/standalone/videos/embed.ts
@@ -262,6 +262,9 @@ export class PeerTubeEmbed {
262 262
263 private async buildDock (videoInfo: VideoDetails, configResponse: Response) { 263 private async buildDock (videoInfo: VideoDetails, configResponse: Response) {
264 if (this.controls) { 264 if (this.controls) {
265 // On webtorrent fallback, player may have been disposed
266 if (!this.player.player_) return
267
265 const title = this.title ? videoInfo.name : undefined 268 const title = this.title ? videoInfo.name : undefined
266 269
267 const config: ServerConfig = await configResponse.json() 270 const config: ServerConfig = await configResponse.json()
diff --git a/package.json b/package.json
index dee9840c7..49d9faf97 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
1{ 1{
2 "name": "peertube", 2 "name": "peertube",
3 "description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.", 3 "description": "Federated (ActivityPub) video streaming platform using P2P (BitTorrent) directly in the web browser with WebTorrent and Angular.",
4 "version": "2.1.0", 4 "version": "2.1.1",
5 "private": true, 5 "private": true,
6 "licence": "AGPL-3.0", 6 "licence": "AGPL-3.0",
7 "engines": { 7 "engines": {
diff --git a/server/controllers/client.ts b/server/controllers/client.ts
index dc3ff18fc..56685f102 100644
--- a/server/controllers/client.ts
+++ b/server/controllers/client.ts
@@ -2,10 +2,11 @@ import * as express from 'express'
2import { join } from 'path' 2import { join } from 'path'
3import { root } from '../helpers/core-utils' 3import { root } from '../helpers/core-utils'
4import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers/constants' 4import { ACCEPT_HEADERS, STATIC_MAX_AGE } from '../initializers/constants'
5import { asyncMiddleware } from '../middlewares' 5import { asyncMiddleware, embedCSP } from '../middlewares'
6import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n' 6import { buildFileLocale, getCompleteLocale, is18nLocale, LOCALE_FILES } from '../../shared/models/i18n/i18n'
7import { ClientHtml } from '../lib/client-html' 7import { ClientHtml } from '../lib/client-html'
8import { logger } from '../helpers/logger' 8import { logger } from '../helpers/logger'
9import { CONFIG } from '@server/initializers/config'
9 10
10const clientsRouter = express.Router() 11const clientsRouter = express.Router()
11 12
@@ -19,8 +20,13 @@ clientsRouter.use('/videos/watch/:id', asyncMiddleware(generateWatchHtmlPage))
19clientsRouter.use('/accounts/:nameWithHost', asyncMiddleware(generateAccountHtmlPage)) 20clientsRouter.use('/accounts/:nameWithHost', asyncMiddleware(generateAccountHtmlPage))
20clientsRouter.use('/video-channels/:nameWithHost', asyncMiddleware(generateVideoChannelHtmlPage)) 21clientsRouter.use('/video-channels/:nameWithHost', asyncMiddleware(generateVideoChannelHtmlPage))
21 22
23const embedCSPMiddleware = CONFIG.CSP.ENABLED
24 ? embedCSP
25 : (req: express.Request, res: express.Response, next: express.NextFunction) => next()
26
22clientsRouter.use( 27clientsRouter.use(
23 '/videos/embed', 28 '/videos/embed',
29 embedCSPMiddleware,
24 (req: express.Request, res: express.Response) => { 30 (req: express.Request, res: express.Response) => {
25 res.removeHeader('X-Frame-Options') 31 res.removeHeader('X-Frame-Options')
26 res.sendFile(embedPath) 32 res.sendFile(embedPath)
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index f802658cf..0b21de0ca 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -176,8 +176,8 @@ async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo
176 if (!info.name) return actor 176 if (!info.name) return actor
177 177
178 if (actor.Avatar) { 178 if (actor.Avatar) {
179 // Don't update the avatar if the filename did not change 179 // Don't update the avatar if the file URL did not change
180 if (actor.Avatar.fileUrl === info.fileUrl) return actor 180 if (info.fileUrl && actor.Avatar.fileUrl === info.fileUrl) return actor
181 181
182 try { 182 try {
183 await actor.Avatar.destroy({ transaction: t }) 183 await actor.Avatar.destroy({ transaction: t })
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts
index 85f22d654..db7fb8568 100644
--- a/server/lib/activitypub/process/process-follow.ts
+++ b/server/lib/activitypub/process/process-follow.ts
@@ -59,7 +59,9 @@ async function processFollow (byActor: MActorSignature, targetActorURL: string)
59 transaction: t 59 transaction: t
60 }) 60 })
61 61
62 if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { 62 // Set the follow as accepted if the remote actor follows a channel or account
63 // Or if the instance automatically accepts followers
64 if (actorFollow.state !== 'accepted' && (isFollowingInstance === false || CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false)) {
63 actorFollow.state = 'accepted' 65 actorFollow.state = 'accepted'
64 await actorFollow.save({ transaction: t }) 66 await actorFollow.save({ transaction: t })
65 } 67 }
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index eacffe186..a91a7663d 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -136,8 +136,7 @@ import {
136 MVideoThumbnailBlacklist, 136 MVideoThumbnailBlacklist,
137 MVideoWithAllFiles, 137 MVideoWithAllFiles,
138 MVideoWithFile, 138 MVideoWithFile,
139 MVideoWithRights, 139 MVideoWithRights
140 MStreamingPlaylistFiles
141} from '../../typings/models' 140} from '../../typings/models'
142import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file' 141import { MVideoFile, MVideoFileStreamingPlaylistVideo } from '../../typings/models/video/video-file'
143import { MThumbnail } from '../../typings/models/video/thumbnail' 142import { MThumbnail } from '../../typings/models/video/thumbnail'
@@ -437,42 +436,31 @@ export type AvailableForListIDsOptions = {
437 } 436 }
438 437
439 if (options.followerActorId) { 438 if (options.followerActorId) {
440 let localVideosReq: WhereOptions = {} 439 let localVideosReq = ''
441 if (options.includeLocalVideos === true) { 440 if (options.includeLocalVideos === true) {
442 localVideosReq = { remote: false } 441 localVideosReq = ' UNION ALL SELECT "video"."id" FROM "video" WHERE remote IS FALSE'
443 } 442 }
444 443
445 // Force actorId to be a number to avoid SQL injections 444 // Force actorId to be a number to avoid SQL injections
446 const actorIdNumber = parseInt(options.followerActorId.toString(), 10) 445 const actorIdNumber = parseInt(options.followerActorId.toString(), 10)
447 whereAnd.push({ 446 whereAnd.push({
448 [Op.or]: [ 447 id: {
449 { 448 [Op.in]: Sequelize.literal(
450 id: { 449 '(' +
451 [ Op.in ]: Sequelize.literal( 450 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
452 '(' + 451 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
453 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' + 452 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
454 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' + 453 ' UNION ALL ' +
455 'WHERE "actorFollow"."actorId" = ' + actorIdNumber + 454 'SELECT "video"."id" AS "id" FROM "video" ' +
456 ')' 455 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
457 ) 456 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
458 } 457 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
459 }, 458 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
460 { 459 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
461 id: { 460 localVideosReq +
462 [ Op.in ]: Sequelize.literal( 461 ')'
463 '(' + 462 )
464 'SELECT "video"."id" AS "id" FROM "video" ' + 463 }
465 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
466 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
467 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
468 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
469 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
470 ')'
471 )
472 }
473 },
474 localVideosReq
475 ]
476 }) 464 })
477 } 465 }
478 466
diff --git a/support/doc/api/openapi.yaml b/support/doc/api/openapi.yaml
index f1cfb81a4..85f1102b4 100644
--- a/support/doc/api/openapi.yaml
+++ b/support/doc/api/openapi.yaml
@@ -1,7 +1,7 @@
1openapi: 3.0.0 1openapi: 3.0.0
2info: 2info:
3 title: PeerTube 3 title: PeerTube
4 version: 2.1.0 4 version: 2.1.1
5 contact: 5 contact:
6 name: PeerTube Community 6 name: PeerTube Community
7 url: 'https://joinpeertube.org' 7 url: 'https://joinpeertube.org'
diff --git a/support/docker/production/Dockerfile.buster b/support/docker/production/Dockerfile.buster
index 515aeb5f1..414bf9aac 100644
--- a/support/docker/production/Dockerfile.buster
+++ b/support/docker/production/Dockerfile.buster
@@ -7,7 +7,7 @@ ARG NPM_RUN_BUILD_OPTS
7 7
8# Install dependencies 8# Install dependencies
9RUN apt update \ 9RUN apt update \
10 && apt install -y --no-install-recommends openssl ffmpeg gnupg gosu \ 10 && apt install -y --no-install-recommends openssl ffmpeg python ca-certificates gnupg gosu \
11 && gosu nobody true \ 11 && gosu nobody true \
12 && rm /var/lib/apt/lists/* -fR 12 && rm /var/lib/apt/lists/* -fR
13 13