Force live type specification in first step
This commit is contained in:
parent
3eb7ee658d
commit
1e2fe802d1
|
@ -16,7 +16,24 @@
|
||||||
></my-select-options>
|
></my-select-options>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group live-type">
|
||||||
|
<div class="peertube-radio-container">
|
||||||
|
<input type="radio" id="permanentLiveFalse" [(ngModel)]="firstStepPermanentLive" [value]="false">
|
||||||
|
<label i18n for="permanentLiveFalse" class="radio">Normal live</label>
|
||||||
|
|
||||||
|
<span class="form-group-description">{{ getNormalLiveDescription() }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="peertube-radio-container">
|
||||||
|
<input type="radio" id="permanentLiveTrue" [(ngModel)]="firstStepPermanentLive" [value]="true">
|
||||||
|
<label i18n for="permanentLiveTrue" class="radio">Permanent/recurring live</label>
|
||||||
|
|
||||||
|
<span class="form-group-description" i18n>{{ getPermanentLiveDescription() }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
[disabled]="firstStepPermanentLive !== true && firstStepPermanentLive !== false"
|
||||||
type="button" i18n-value value="Go Live" (click)="goLive()"
|
type="button" i18n-value value="Go Live" (click)="goLive()"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
.live-type {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.peertube-radio-container {
|
||||||
|
width: 250px;
|
||||||
|
|
||||||
|
.form-group-description {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
import { forkJoin } from 'rxjs'
|
import { forkJoin } from 'rxjs'
|
||||||
import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
|
import { AfterViewInit, Component, EventEmitter, OnInit, Output } from '@angular/core'
|
||||||
import { Router } from '@angular/router'
|
import { Router } from '@angular/router'
|
||||||
|
@ -16,6 +15,7 @@ import { VideoSend } from './video-send'
|
||||||
templateUrl: './video-go-live.component.html',
|
templateUrl: './video-go-live.component.html',
|
||||||
styleUrls: [
|
styleUrls: [
|
||||||
'../shared/video-edit.component.scss',
|
'../shared/video-edit.component.scss',
|
||||||
|
'./video-go-live.component.scss',
|
||||||
'./video-send.scss'
|
'./video-send.scss'
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -23,6 +23,8 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
|
||||||
@Output() firstStepDone = new EventEmitter<string>()
|
@Output() firstStepDone = new EventEmitter<string>()
|
||||||
@Output() firstStepError = new EventEmitter<void>()
|
@Output() firstStepError = new EventEmitter<void>()
|
||||||
|
|
||||||
|
firstStepPermanentLive: boolean
|
||||||
|
|
||||||
isInUpdateForm = false
|
isInUpdateForm = false
|
||||||
|
|
||||||
liveVideo: LiveVideo
|
liveVideo: LiveVideo
|
||||||
|
@ -70,8 +72,8 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
|
||||||
waitTranscoding: true,
|
waitTranscoding: true,
|
||||||
commentsEnabled: true,
|
commentsEnabled: true,
|
||||||
downloadEnabled: true,
|
downloadEnabled: true,
|
||||||
permanentLive: false,
|
permanentLive: this.firstStepPermanentLive,
|
||||||
saveReplay: false,
|
saveReplay: this.firstStepPermanentLive === false && this.isReplayAllowed(),
|
||||||
channelId: this.firstStepChannelId
|
channelId: this.firstStepChannelId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +156,26 @@ export class VideoGoLiveComponent extends VideoSend implements OnInit, AfterView
|
||||||
return this.form.value['saveReplay'] === true
|
return this.form.value['saveReplay'] === true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNormalLiveDescription () {
|
||||||
|
if (this.isReplayAllowed()) {
|
||||||
|
return $localize`Stream only once and save a replay of your live`
|
||||||
|
}
|
||||||
|
|
||||||
|
return $localize`Stream only once`
|
||||||
|
}
|
||||||
|
|
||||||
|
getPermanentLiveDescription () {
|
||||||
|
if (this.isReplayAllowed()) {
|
||||||
|
return $localize`Stream multiple times, replays can't be saved`
|
||||||
|
}
|
||||||
|
|
||||||
|
return $localize`Stream multiple times using the same URL`
|
||||||
|
}
|
||||||
|
|
||||||
|
private isReplayAllowed () {
|
||||||
|
return this.serverConfig.live.allowReplay
|
||||||
|
}
|
||||||
|
|
||||||
private fetchVideoLive () {
|
private fetchVideoLive () {
|
||||||
this.liveVideoService.getVideoLive(this.videoId)
|
this.liveVideoService.getVideoLive(this.videoId)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@use '_variables' as *;
|
@use '_variables' as *;
|
||||||
@use '_mixins' as *;
|
@use '_mixins' as *;
|
||||||
|
|
||||||
$width-size: 190px;
|
$width-size: 250px;
|
||||||
|
|
||||||
.alert.alert-danger {
|
.alert.alert-danger {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -29,6 +29,7 @@ $width-size: 190px;
|
||||||
my-select-options ::ng-deep ng-select,
|
my-select-options ::ng-deep ng-select,
|
||||||
my-select-channel ::ng-deep ng-select {
|
my-select-channel ::ng-deep ng-select {
|
||||||
width: $width-size;
|
width: $width-size;
|
||||||
|
|
||||||
@media screen and (max-width: $width-size) {
|
@media screen and (max-width: $width-size) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ export const VIDEO_SUPPORT_VALIDATOR: BuildFormValidator = {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const VIDEO_SCHEDULE_PUBLICATION_AT_VALIDATOR: BuildFormValidator = {
|
export const VIDEO_SCHEDULE_PUBLICATION_AT_VALIDATOR: BuildFormValidator = {
|
||||||
VALIDATORS: [ ],
|
VALIDATORS: [ ], // Required is set dynamically
|
||||||
MESSAGES: {
|
MESSAGES: {
|
||||||
required: $localize`A date is required to schedule video update.`
|
required: $localize`A date is required to schedule video update.`
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,10 @@
|
||||||
|
|
||||||
$form-base-input-width: auto;
|
$form-base-input-width: auto;
|
||||||
|
|
||||||
|
.text-muted {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
ng-select {
|
ng-select {
|
||||||
width: $form-base-input-width;
|
width: $form-base-input-width;
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
<div class="modal-body" *ngIf="live">
|
<div class="modal-body" *ngIf="live">
|
||||||
<div>
|
<div>
|
||||||
<div class="badge badge-info" *ngIf="live.permanentLive" i18n>Permanent live</div>
|
<div class="badge badge-info" *ngIf="live.permanentLive" i18n>Permanent/Recurring live</div>
|
||||||
<div class="badge badge-info" *ngIf="live.saveReplay" i18n>Replay will be saved</div>
|
<div class="badge badge-info" *ngIf="live.saveReplay" i18n>Replay will be saved</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -478,7 +478,7 @@
|
||||||
|
|
||||||
.form-group-description {
|
.form-group-description {
|
||||||
display: block;
|
display: block;
|
||||||
margin-top: -10px;
|
margin-top: -7px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
margin-left: 29px;
|
margin-left: 29px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,7 +119,7 @@ export abstract class APVideoAbstractBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async setStreamingPlaylists (video: MVideoFullLight, t: Transaction) {
|
protected async setStreamingPlaylists (video: MVideoFullLight, t: Transaction) {
|
||||||
const streamingPlaylistAttributes = getStreamingPlaylistAttributesFromObject(video, this.videoObject, video.VideoFiles || [])
|
const streamingPlaylistAttributes = getStreamingPlaylistAttributesFromObject(video, this.videoObject)
|
||||||
const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a))
|
const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a))
|
||||||
|
|
||||||
// Remove video playlists that do not exist anymore
|
// Remove video playlists that do not exist anymore
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { VideoCaptionModel } from '@server/models/video/video-caption'
|
||||||
import { VideoFileModel } from '@server/models/video/video-file'
|
import { VideoFileModel } from '@server/models/video/video-file'
|
||||||
import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist'
|
import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist'
|
||||||
import { FilteredModelAttributes } from '@server/types'
|
import { FilteredModelAttributes } from '@server/types'
|
||||||
import { isStreamingPlaylist, MChannelId, MStreamingPlaylistVideo, MVideo, MVideoFile, MVideoId } from '@server/types/models'
|
import { isStreamingPlaylist, MChannelId, MStreamingPlaylistVideo, MVideo, MVideoId } from '@server/types/models'
|
||||||
import {
|
import {
|
||||||
ActivityHashTagObject,
|
ActivityHashTagObject,
|
||||||
ActivityMagnetUrlObject,
|
ActivityMagnetUrlObject,
|
||||||
|
@ -110,7 +110,7 @@ function getFileAttributesFromUrl (
|
||||||
return attributes
|
return attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStreamingPlaylistAttributesFromObject (video: MVideoId, videoObject: VideoObject, videoFiles: MVideoFile[]) {
|
function getStreamingPlaylistAttributesFromObject (video: MVideoId, videoObject: VideoObject) {
|
||||||
const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[]
|
const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[]
|
||||||
if (playlistUrls.length === 0) return []
|
if (playlistUrls.length === 0) return []
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ function getStreamingPlaylistAttributesFromObject (video: MVideoId, videoObject:
|
||||||
for (const playlistUrlObject of playlistUrls) {
|
for (const playlistUrlObject of playlistUrls) {
|
||||||
const segmentsSha256UrlObject = playlistUrlObject.tag.find(isAPPlaylistSegmentHashesUrlObject)
|
const segmentsSha256UrlObject = playlistUrlObject.tag.find(isAPPlaylistSegmentHashesUrlObject)
|
||||||
|
|
||||||
let files: unknown[] = playlistUrlObject.tag.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[]
|
const files: unknown[] = playlistUrlObject.tag.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[]
|
||||||
|
|
||||||
if (!segmentsSha256UrlObject) {
|
if (!segmentsSha256UrlObject) {
|
||||||
logger.warn('No segment sha256 URL found in AP playlist object.', { playlistUrl: playlistUrlObject })
|
logger.warn('No segment sha256 URL found in AP playlist object.', { playlistUrl: playlistUrlObject })
|
||||||
|
|
Loading…
Reference in New Issue