Merge branch 'release/4.2.0' into develop
This commit is contained in:
commit
e771ff815d
|
@ -17,6 +17,7 @@
|
||||||
* Add `client.videos.resumable_upload.max_chunk_size` config option [#4857](https://github.com/Chocobozzz/PeerTube/pull/4857)
|
* Add `client.videos.resumable_upload.max_chunk_size` config option [#4857](https://github.com/Chocobozzz/PeerTube/pull/4857)
|
||||||
* Add `object_storage.upload_acl` config option [#4861](https://github.com/Chocobozzz/PeerTube/pull/4861)
|
* Add `object_storage.upload_acl` config option [#4861](https://github.com/Chocobozzz/PeerTube/pull/4861)
|
||||||
* Add ability to set RTMP/RTMPS listening hostname using `rtmp.hostname`/`rtmps.hostname` and public RTMP/RTMPS hostname using `rtmp.public_hostname`/`rtmps.public_hostname`
|
* Add ability to set RTMP/RTMPS listening hostname using `rtmp.hostname`/`rtmps.hostname` and public RTMP/RTMPS hostname using `rtmp.public_hostname`/`rtmps.public_hostname`
|
||||||
|
* Removed `best` default trending algorithm. It is automatically used if using `hot` algorithm with a logged in user
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,10 @@
|
||||||
This live has ended.
|
This live has ended.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div i18n class="alert alert-warning" *ngIf="noPlaylistVideoFound">
|
||||||
|
There are no videos available in this playlist.
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="alert alert-danger" *ngIf="video?.blacklisted">
|
<div class="alert alert-danger" *ngIf="video?.blacklisted">
|
||||||
<div class="blocked-label" i18n>This video is blocked.</div>
|
<div class="blocked-label" i18n>This video is blocked.</div>
|
||||||
{{ video.blacklistedReason }}
|
{{ video.blacklistedReason }}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { VideoState } from '@shared/models'
|
||||||
})
|
})
|
||||||
export class VideoAlertComponent {
|
export class VideoAlertComponent {
|
||||||
@Input() video: VideoDetails
|
@Input() video: VideoDetails
|
||||||
|
@Input() noPlaylistVideoFound: boolean
|
||||||
|
|
||||||
isVideoToTranscode () {
|
isVideoToTranscode () {
|
||||||
return this.video && this.video.state.id === VideoState.TO_TRANSCODE
|
return this.video && this.video.state.id === VideoState.TO_TRANSCODE
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<div
|
<div
|
||||||
*ngIf="playlist && currentPlaylistPosition" class="playlist"
|
*ngIf="playlist && (currentPlaylistPosition || noPlaylistVideos)" class="playlist"
|
||||||
myInfiniteScroller [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()"
|
myInfiniteScroller [onItself]="true" (nearOfBottom)="onPlaylistVideosNearOfBottom()"
|
||||||
>
|
>
|
||||||
<div class="playlist-info">
|
<div class="playlist-info">
|
||||||
|
|
|
@ -18,6 +18,7 @@ export class VideoWatchPlaylistComponent {
|
||||||
@Input() playlist: VideoPlaylist
|
@Input() playlist: VideoPlaylist
|
||||||
|
|
||||||
@Output() videoFound = new EventEmitter<string>()
|
@Output() videoFound = new EventEmitter<string>()
|
||||||
|
@Output() noVideoFound = new EventEmitter<void>()
|
||||||
|
|
||||||
playlistElements: VideoPlaylistElement[] = []
|
playlistElements: VideoPlaylistElement[] = []
|
||||||
playlistPagination: ComponentPagination = {
|
playlistPagination: ComponentPagination = {
|
||||||
|
@ -28,10 +29,11 @@ export class VideoWatchPlaylistComponent {
|
||||||
|
|
||||||
autoPlayNextVideoPlaylist: boolean
|
autoPlayNextVideoPlaylist: boolean
|
||||||
autoPlayNextVideoPlaylistSwitchText = ''
|
autoPlayNextVideoPlaylistSwitchText = ''
|
||||||
|
|
||||||
loopPlaylist: boolean
|
loopPlaylist: boolean
|
||||||
loopPlaylistSwitchText = ''
|
loopPlaylistSwitchText = ''
|
||||||
noPlaylistVideos = false
|
|
||||||
|
|
||||||
|
noPlaylistVideos = false
|
||||||
currentPlaylistPosition: number
|
currentPlaylistPosition: number
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
|
@ -100,6 +102,7 @@ export class VideoWatchPlaylistComponent {
|
||||||
const firstAvailableVideo = this.playlistElements.find(e => !!e.video)
|
const firstAvailableVideo = this.playlistElements.find(e => !!e.video)
|
||||||
if (!firstAvailableVideo) {
|
if (!firstAvailableVideo) {
|
||||||
this.noPlaylistVideos = true
|
this.noPlaylistVideos = true
|
||||||
|
this.noVideoFound.emit()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,15 @@
|
||||||
<img class="placeholder-image" *ngIf="playerPlaceholderImgSrc" [src]="playerPlaceholderImgSrc" alt="Placeholder image" i18n-alt>
|
<img class="placeholder-image" *ngIf="playerPlaceholderImgSrc" [src]="playerPlaceholderImgSrc" alt="Placeholder image" i18n-alt>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-video-watch-playlist #videoWatchPlaylist [playlist]="playlist" (videoFound)="onPlaylistVideoFound($event)"></my-video-watch-playlist>
|
<my-video-watch-playlist
|
||||||
|
#videoWatchPlaylist [playlist]="playlist"
|
||||||
|
(noVideoFound)="onPlaylistNoVideoFound()" (videoFound)="onPlaylistVideoFound($event)"
|
||||||
|
></my-video-watch-playlist>
|
||||||
|
|
||||||
<my-plugin-placeholder pluginId="player-next"></my-plugin-placeholder>
|
<my-plugin-placeholder pluginId="player-next"></my-plugin-placeholder>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-video-alert [video]="video"></my-video-alert>
|
<my-video-alert [video]="video" [noPlaylistVideoFound]="noPlaylistVideoFound"></my-video-alert>
|
||||||
|
|
||||||
<!-- Video information -->
|
<!-- Video information -->
|
||||||
<div *ngIf="video" class="margin-content video-bottom">
|
<div *ngIf="video" class="margin-content video-bottom">
|
||||||
|
|
|
@ -72,6 +72,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
playlist: VideoPlaylist = null
|
playlist: VideoPlaylist = null
|
||||||
|
|
||||||
remoteServerDown = false
|
remoteServerDown = false
|
||||||
|
noPlaylistVideoFound = false
|
||||||
|
|
||||||
private nextVideoUUID = ''
|
private nextVideoUUID = ''
|
||||||
private nextVideoTitle = ''
|
private nextVideoTitle = ''
|
||||||
|
@ -178,6 +179,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
this.loadVideo(videoId)
|
this.loadVideo(videoId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onPlaylistNoVideoFound () {
|
||||||
|
this.noPlaylistVideoFound = true
|
||||||
|
}
|
||||||
|
|
||||||
isUserLoggedIn () {
|
isUserLoggedIn () {
|
||||||
return this.authService.isLoggedIn()
|
return this.authService.isLoggedIn()
|
||||||
}
|
}
|
||||||
|
@ -286,6 +291,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
|
||||||
private loadPlaylist (playlistId: string) {
|
private loadPlaylist (playlistId: string) {
|
||||||
if (this.isSameElement(this.playlist, playlistId)) return
|
if (this.isSameElement(this.playlist, playlistId)) return
|
||||||
|
|
||||||
|
this.noPlaylistVideoFound = false
|
||||||
|
|
||||||
this.playlistService.getVideoPlaylist(playlistId)
|
this.playlistService.getVideoPlaylist(playlistId)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: playlist => {
|
next: playlist => {
|
||||||
|
|
|
@ -173,6 +173,10 @@ export class VideosListCommonPageComponent implements OnInit, OnDestroy, Disable
|
||||||
case 'most-liked':
|
case 'most-liked':
|
||||||
return '-likes'
|
return '-likes'
|
||||||
|
|
||||||
|
// We'll automatically apply "best" sort if using "hot" sort with a logged user
|
||||||
|
case 'best':
|
||||||
|
return '-hot'
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return '-' + algorithm as VideoSortField
|
return '-' + algorithm as VideoSortField
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,6 @@ trending:
|
||||||
interval_days: 7 # Compute trending videos for the last x days
|
interval_days: 7 # Compute trending videos for the last x days
|
||||||
algorithms:
|
algorithms:
|
||||||
enabled:
|
enabled:
|
||||||
- 'best' # adaptation of Reddit's 'Best' algorithm (Hot minus History)
|
|
||||||
- 'hot' # adaptation of Reddit's 'Hot' algorithm
|
- 'hot' # adaptation of Reddit's 'Hot' algorithm
|
||||||
- 'most-viewed' # default, used initially by PeerTube as the trending page
|
- 'most-viewed' # default, used initially by PeerTube as the trending page
|
||||||
- 'most-liked'
|
- 'most-liked'
|
||||||
|
|
|
@ -177,7 +177,6 @@ trending:
|
||||||
interval_days: 7 # Compute trending videos for the last x days
|
interval_days: 7 # Compute trending videos for the last x days
|
||||||
algorithms:
|
algorithms:
|
||||||
enabled:
|
enabled:
|
||||||
- 'best' # adaptation of Reddit's 'Best' algorithm (Hot minus History)
|
|
||||||
- 'hot' # adaptation of Reddit's 'Hot' algorithm
|
- 'hot' # adaptation of Reddit's 'Hot' algorithm
|
||||||
- 'most-viewed' # default, used initially by PeerTube as the trending page
|
- 'most-viewed' # default, used initially by PeerTube as the trending page
|
||||||
- 'most-liked'
|
- 'most-liked'
|
||||||
|
|
|
@ -86,7 +86,9 @@ async function downloadVideoFile (req: express.Request, res: express.Response) {
|
||||||
}
|
}
|
||||||
|
|
||||||
await VideoPathManager.Instance.makeAvailableVideoFile(videoFile.withVideoOrPlaylist(video), path => {
|
await VideoPathManager.Instance.makeAvailableVideoFile(videoFile.withVideoOrPlaylist(video), path => {
|
||||||
const filename = `${video.name}-${videoFile.resolution}p${videoFile.extname}`
|
// Express uses basename on filename parameter
|
||||||
|
const videoName = video.name.replace(/[/\\]/g, '_')
|
||||||
|
const filename = `${videoName}-${videoFile.resolution}p${videoFile.extname}`
|
||||||
|
|
||||||
return res.download(path, filename)
|
return res.download(path, filename)
|
||||||
})
|
})
|
||||||
|
|
|
@ -165,7 +165,7 @@ describe('Test config API validators', function () {
|
||||||
trending: {
|
trending: {
|
||||||
videos: {
|
videos: {
|
||||||
algorithms: {
|
algorithms: {
|
||||||
enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ],
|
enabled: [ 'hot', 'most-viewed', 'most-liked' ],
|
||||||
default: 'most-viewed'
|
default: 'most-viewed'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,7 +367,7 @@ const newCustomConfig: CustomConfig = {
|
||||||
trending: {
|
trending: {
|
||||||
videos: {
|
videos: {
|
||||||
algorithms: {
|
algorithms: {
|
||||||
enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ],
|
enabled: [ 'hot', 'most-viewed', 'most-liked' ],
|
||||||
default: 'hot'
|
default: 'hot'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,7 +356,7 @@ export class ConfigCommand extends AbstractCommand {
|
||||||
trending: {
|
trending: {
|
||||||
videos: {
|
videos: {
|
||||||
algorithms: {
|
algorithms: {
|
||||||
enabled: [ 'best', 'hot', 'most-viewed', 'most-liked' ],
|
enabled: [ 'hot', 'most-viewed', 'most-liked' ],
|
||||||
default: 'hot'
|
default: 'hot'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue