mirror of https://github.com/Chocobozzz/PeerTube
Update playlist add component to accept multiple times the same video
parent
cbb513e737
commit
e79df4eefb
|
@ -1,4 +1,4 @@
|
|||
import { ChangeDetectorRef, Component, forwardRef, Input, OnInit } from '@angular/core'
|
||||
import { ChangeDetectorRef, Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'
|
||||
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'
|
||||
import { secondsToTime, timeToInt } from '../../../assets/player/utils'
|
||||
|
||||
|
@ -19,6 +19,8 @@ export class TimestampInputComponent implements ControlValueAccessor, OnInit {
|
|||
@Input() timestamp: number
|
||||
@Input() disabled = false
|
||||
|
||||
@Output() inputBlur = new EventEmitter()
|
||||
|
||||
timestampString: string
|
||||
|
||||
constructor (private changeDetector: ChangeDetectorRef) {}
|
||||
|
@ -57,5 +59,7 @@ export class TimestampInputComponent implements ControlValueAccessor, OnInit {
|
|||
|
||||
this.propagateChange(this.timestamp)
|
||||
}
|
||||
|
||||
this.inputBlur.emit()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,42 +2,6 @@
|
|||
<div class="header">
|
||||
<div class="first-row">
|
||||
<div i18n class="title">Save to</div>
|
||||
|
||||
<div class="options" (click)="displayOptions = !displayOptions">
|
||||
<my-global-icon iconName="cog" aria-hidden="true"></my-global-icon>
|
||||
|
||||
<span i18n>Options</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options-row" *ngIf="displayOptions">
|
||||
<div>
|
||||
<my-peertube-checkbox
|
||||
inputName="startAt" [(ngModel)]="timestampOptions.startTimestampEnabled"
|
||||
i18n-labelText labelText="Start at"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<my-timestamp-input
|
||||
[timestamp]="timestampOptions.startTimestamp"
|
||||
[maxTimestamp]="video.duration"
|
||||
[disabled]="!timestampOptions.startTimestampEnabled"
|
||||
[(ngModel)]="timestampOptions.startTimestamp"
|
||||
></my-timestamp-input>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<my-peertube-checkbox
|
||||
inputName="stopAt" [(ngModel)]="timestampOptions.stopTimestampEnabled"
|
||||
i18n-labelText labelText="Stop at"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<my-timestamp-input
|
||||
[timestamp]="timestampOptions.stopTimestamp"
|
||||
[maxTimestamp]="video.duration"
|
||||
[disabled]="!timestampOptions.stopTimestampEnabled"
|
||||
[(ngModel)]="timestampOptions.stopTimestamp"
|
||||
></my-timestamp-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -46,14 +10,52 @@
|
|||
</div>
|
||||
|
||||
<div class="playlists">
|
||||
<div class="playlist dropdown-item" *ngFor="let playlist of videoPlaylists" (click)="togglePlaylist($event, playlist)">
|
||||
<my-peertube-checkbox [inputName]="'in-playlist-' + playlist.id" [(ngModel)]="playlist.inPlaylist" [onPushWorkaround]="true"></my-peertube-checkbox>
|
||||
<div
|
||||
*ngFor="let playlist of videoPlaylists"
|
||||
class="playlist dropdown-item" [ngClass]="{ 'has-optional-row': playlist.optionalRowDisplayed }"
|
||||
>
|
||||
<div class="primary-row">
|
||||
<my-peertube-checkbox
|
||||
[disabled]="isPresentMultipleTimes(playlist) || playlist.optionalRowDisplayed" [inputName]="getPrimaryInputName(playlist)"
|
||||
[ngModel]="isPrimaryCheckboxChecked(playlist)" [onPushWorkaround]="true"
|
||||
(click)="toggleMainPlaylist($event, playlist)"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<div class="display-name">
|
||||
{{ playlist.displayName }}
|
||||
<label class="display-name" (click)="toggleMainPlaylist($event, playlist)">
|
||||
{{ playlist.displayName }}
|
||||
</label>
|
||||
|
||||
<div *ngIf="playlist.inPlaylist && (playlist.startTimestamp || playlist.stopTimestamp)" class="timestamp-info">
|
||||
{{ formatTimestamp(playlist) }}
|
||||
<div class="optional-row-icon" *ngIf="isPrimaryCheckboxChecked(playlist)" (click)="toggleOptionalRow(playlist)">
|
||||
<my-global-icon iconName="add" aria-hidden="true"></my-global-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="optional-rows" *ngIf="playlist.optionalRowDisplayed">
|
||||
<div class="labels">
|
||||
<div i18n>Start at</div>
|
||||
<div i18n>Stop at</div>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let element of buildOptionalRowElements(playlist)">
|
||||
<my-peertube-checkbox
|
||||
[inputName]="getOptionalInputName(playlist, element)"
|
||||
[ngModel]="element.enabled" [onPushWorkaround]="true"
|
||||
(click)="toggleOptionalPlaylist($event, playlist, element, startAt.timestamp, stopAt.timestamp)"
|
||||
></my-peertube-checkbox>
|
||||
|
||||
<my-timestamp-input
|
||||
[maxTimestamp]="video.duration"
|
||||
[(ngModel)]="element.startTimestamp"
|
||||
(inputBlur)="onElementTimestampUpdate(playlist, element)"
|
||||
#startAt
|
||||
></my-timestamp-input>
|
||||
|
||||
<my-timestamp-input
|
||||
[maxTimestamp]="video.duration"
|
||||
[(ngModel)]="element.stopTimestamp"
|
||||
(inputBlur)="onElementTimestampUpdate(playlist, element)"
|
||||
#stopAt
|
||||
></my-timestamp-input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
@import '_variables';
|
||||
@import '_mixins';
|
||||
|
||||
$optional-rows-checkbox-width: 34px;
|
||||
$timestamp-width: 50px;
|
||||
$timestamp-margin-right: 10px;
|
||||
|
||||
.header,
|
||||
.dropdown-item,
|
||||
.input-container {
|
||||
|
@ -24,31 +28,6 @@
|
|||
font-size: 18px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
my-global-icon {
|
||||
@include apply-svg-color(#333);
|
||||
|
||||
width: 16px;
|
||||
height: 23px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.options-row {
|
||||
margin-top: 10px;
|
||||
padding-left: 10px;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,8 +37,16 @@
|
|||
}
|
||||
|
||||
.playlist {
|
||||
display: inline-flex;
|
||||
cursor: pointer;
|
||||
padding: 8px 10px 8px 24px;
|
||||
|
||||
&.has-optional-row:hover {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.primary-row,
|
||||
.optional-rows > div {
|
||||
display: flex;
|
||||
|
||||
my-peertube-checkbox {
|
||||
margin-right: 10px;
|
||||
|
@ -69,11 +56,58 @@
|
|||
.display-name {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
flex-grow: 1;
|
||||
margin: 0;
|
||||
font-weight: $font-regular;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.timestamp-info {
|
||||
font-size: 0.9em;
|
||||
color: pvar(--greyForegroundColor);
|
||||
margin-left: 5px;
|
||||
.optional-row-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
|
||||
my-global-icon {
|
||||
@include apply-svg-color(#333);
|
||||
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
my-timestamp-input {
|
||||
margin-right: $timestamp-margin-right;
|
||||
|
||||
::ng-deep .ui-inputtext {
|
||||
padding: 0;
|
||||
width: $timestamp-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.optional-rows {
|
||||
> div {
|
||||
padding: 8px 5px 5px 10px;
|
||||
}
|
||||
|
||||
my-peertube-checkbox {
|
||||
display: block;
|
||||
width: $optional-rows-checkbox-width;
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
.labels {
|
||||
margin-left: $optional-rows-checkbox-width;
|
||||
font-size: 13px;
|
||||
color: pvar(--greyForegroundColor);
|
||||
padding-top: 5px;
|
||||
padding-bottom: 0;
|
||||
|
||||
div {
|
||||
margin-right: $timestamp-margin-right;
|
||||
width: $timestamp-width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,23 +4,29 @@ import { debounceTime, filter } from 'rxjs/operators'
|
|||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'
|
||||
import { AuthService, DisableForReuseHook, Notifier } from '@app/core'
|
||||
import { FormReactive, FormValidatorService } from '@app/shared/shared-forms'
|
||||
import { Video, VideoExistInPlaylist, VideoPlaylistCreate, VideoPlaylistElementCreate, VideoPlaylistPrivacy } from '@shared/models'
|
||||
import { Video, VideoExistInPlaylist, VideoPlaylistCreate, VideoPlaylistElementCreate, VideoPlaylistPrivacy, VideoPlaylistElementUpdate } from '@shared/models'
|
||||
import { secondsToTime } from '../../../assets/player/utils'
|
||||
import { VIDEO_PLAYLIST_DISPLAY_NAME_VALIDATOR } from '../form-validators/video-playlist-validators'
|
||||
import { CachedPlaylist, VideoPlaylistService } from './video-playlist.service'
|
||||
import { invoke, last } from 'lodash'
|
||||
|
||||
const logger = debug('peertube:playlists:VideoAddToPlaylistComponent')
|
||||
|
||||
type PlaylistSummary = {
|
||||
id: number
|
||||
inPlaylist: boolean
|
||||
displayName: string
|
||||
|
||||
type PlaylistElement = {
|
||||
enabled: boolean
|
||||
playlistElementId?: number
|
||||
startTimestamp?: number
|
||||
stopTimestamp?: number
|
||||
}
|
||||
|
||||
type PlaylistSummary = {
|
||||
id: number
|
||||
displayName: string
|
||||
optionalRowDisplayed: boolean
|
||||
|
||||
elements: PlaylistElement[]
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'my-video-add-to-playlist',
|
||||
styleUrls: [ './video-add-to-playlist.component.scss' ],
|
||||
|
@ -33,16 +39,11 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
@Input() lazyLoad = false
|
||||
|
||||
isNewPlaylistBlockOpened = false
|
||||
|
||||
videoPlaylistSearch: string
|
||||
videoPlaylistSearchChanged = new Subject<string>()
|
||||
|
||||
videoPlaylists: PlaylistSummary[] = []
|
||||
timestampOptions: {
|
||||
startTimestampEnabled: boolean
|
||||
startTimestamp: number
|
||||
stopTimestampEnabled: boolean
|
||||
stopTimestamp: number
|
||||
}
|
||||
displayOptions = false
|
||||
|
||||
private disabled = false
|
||||
|
||||
|
@ -106,7 +107,6 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
this.videoPlaylists = []
|
||||
this.videoPlaylistSearch = undefined
|
||||
|
||||
this.resetOptions(true)
|
||||
this.load()
|
||||
|
||||
this.cd.markForCheck()
|
||||
|
@ -115,7 +115,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
load () {
|
||||
logger('Loading component')
|
||||
|
||||
this.listenToPlaylistChanges()
|
||||
this.listenToVideoPlaylistChange()
|
||||
|
||||
this.videoPlaylistService.listMyPlaylistWithCache(this.user, this.videoPlaylistSearch)
|
||||
.subscribe(playlistsResult => {
|
||||
|
@ -128,7 +128,6 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
openChange (opened: boolean) {
|
||||
if (opened === false) {
|
||||
this.isNewPlaylistBlockOpened = false
|
||||
this.displayOptions = false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,17 +137,49 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
this.isNewPlaylistBlockOpened = true
|
||||
}
|
||||
|
||||
togglePlaylist (event: Event, playlist: PlaylistSummary) {
|
||||
event.preventDefault()
|
||||
toggleMainPlaylist (e: Event, playlist: PlaylistSummary) {
|
||||
e.preventDefault()
|
||||
|
||||
if (playlist.inPlaylist === true) {
|
||||
this.removeVideoFromPlaylist(playlist)
|
||||
if (this.isPresentMultipleTimes(playlist) || playlist.optionalRowDisplayed) return
|
||||
|
||||
if (playlist.elements.length === 0) {
|
||||
const element: PlaylistElement = {
|
||||
enabled: true,
|
||||
playlistElementId: undefined,
|
||||
startTimestamp: 0,
|
||||
stopTimestamp: this.video.duration
|
||||
}
|
||||
|
||||
this.addVideoInPlaylist(playlist, element)
|
||||
} else {
|
||||
this.addVideoInPlaylist(playlist)
|
||||
this.removeVideoFromPlaylist(playlist, playlist.elements[0].playlistElementId)
|
||||
playlist.elements = []
|
||||
}
|
||||
|
||||
playlist.inPlaylist = !playlist.inPlaylist
|
||||
this.resetOptions()
|
||||
this.cd.markForCheck()
|
||||
}
|
||||
|
||||
toggleOptionalPlaylist (e: Event, playlist: PlaylistSummary, element: PlaylistElement, startTimestamp: number, stopTimestamp: number) {
|
||||
e.preventDefault()
|
||||
|
||||
if (element.enabled) {
|
||||
this.removeVideoFromPlaylist(playlist, element.playlistElementId)
|
||||
element.enabled = false
|
||||
|
||||
// Hide optional rows pane when the user unchecked all the playlists
|
||||
if (this.isPrimaryCheckboxChecked(playlist) === false) {
|
||||
playlist.optionalRowDisplayed = false
|
||||
}
|
||||
} else {
|
||||
const element: PlaylistElement = {
|
||||
enabled: true,
|
||||
playlistElementId: undefined,
|
||||
startTimestamp,
|
||||
stopTimestamp
|
||||
}
|
||||
|
||||
this.addVideoInPlaylist(playlist, element)
|
||||
}
|
||||
|
||||
this.cd.markForCheck()
|
||||
}
|
||||
|
@ -172,34 +203,99 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
)
|
||||
}
|
||||
|
||||
resetOptions (resetTimestamp = false) {
|
||||
this.displayOptions = false
|
||||
|
||||
this.timestampOptions = {} as any
|
||||
this.timestampOptions.startTimestampEnabled = false
|
||||
this.timestampOptions.stopTimestampEnabled = false
|
||||
|
||||
if (resetTimestamp) {
|
||||
this.timestampOptions.startTimestamp = 0
|
||||
this.timestampOptions.stopTimestamp = this.video.duration
|
||||
}
|
||||
}
|
||||
|
||||
formatTimestamp (playlist: PlaylistSummary) {
|
||||
const start = playlist.startTimestamp ? secondsToTime(playlist.startTimestamp) : ''
|
||||
const stop = playlist.stopTimestamp ? secondsToTime(playlist.stopTimestamp) : ''
|
||||
|
||||
return `(${start}-${stop})`
|
||||
}
|
||||
|
||||
onVideoPlaylistSearchChanged () {
|
||||
this.videoPlaylistSearchChanged.next()
|
||||
}
|
||||
|
||||
private removeVideoFromPlaylist (playlist: PlaylistSummary) {
|
||||
if (!playlist.playlistElementId) return
|
||||
isPrimaryCheckboxChecked (playlist: PlaylistSummary) {
|
||||
return playlist.elements.filter(e => e.enabled)
|
||||
.length !== 0
|
||||
}
|
||||
|
||||
this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, playlist.playlistElementId, this.video.id)
|
||||
toggleOptionalRow (playlist: PlaylistSummary) {
|
||||
playlist.optionalRowDisplayed = !playlist.optionalRowDisplayed
|
||||
|
||||
this.cd.markForCheck()
|
||||
}
|
||||
|
||||
getPrimaryInputName (playlist: PlaylistSummary) {
|
||||
return 'in-playlist-primary-' + playlist.id
|
||||
}
|
||||
|
||||
getOptionalInputName (playlist: PlaylistSummary, element?: PlaylistElement) {
|
||||
const suffix = element
|
||||
? '-' + element.playlistElementId
|
||||
: ''
|
||||
|
||||
return 'in-playlist-optional-' + playlist.id + suffix
|
||||
}
|
||||
|
||||
buildOptionalRowElements (playlist: PlaylistSummary) {
|
||||
const elements = playlist.elements
|
||||
|
||||
const lastElement = elements.length === 0
|
||||
? undefined
|
||||
: elements[elements.length - 1]
|
||||
|
||||
// Build an empty last element
|
||||
if (!lastElement || lastElement.enabled === true) {
|
||||
elements.push({
|
||||
enabled: false,
|
||||
startTimestamp: 0,
|
||||
stopTimestamp: this.video.duration
|
||||
})
|
||||
}
|
||||
|
||||
return elements
|
||||
}
|
||||
|
||||
isPresentMultipleTimes (playlist: PlaylistSummary) {
|
||||
return playlist.elements.filter(e => e.enabled === true).length > 1
|
||||
}
|
||||
|
||||
onElementTimestampUpdate (playlist: PlaylistSummary, element: PlaylistElement) {
|
||||
if (!element.playlistElementId || element.enabled === false) return
|
||||
|
||||
const body: VideoPlaylistElementUpdate = {
|
||||
startTimestamp: element.startTimestamp,
|
||||
stopTimestamp: element.stopTimestamp
|
||||
}
|
||||
|
||||
this.videoPlaylistService.updateVideoOfPlaylist(playlist.id, element.playlistElementId, body, this.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success($localize`Timestamps updated`)
|
||||
},
|
||||
|
||||
err => {
|
||||
this.notifier.error(err.message)
|
||||
},
|
||||
|
||||
() => this.cd.markForCheck()
|
||||
)
|
||||
}
|
||||
|
||||
private isOptionalRowDisplayed (playlist: PlaylistSummary) {
|
||||
const elements = playlist.elements.filter(e => e.enabled)
|
||||
|
||||
if (elements.length > 1) return true
|
||||
|
||||
if (elements.length === 1) {
|
||||
const element = elements[0]
|
||||
|
||||
if (
|
||||
(element.startTimestamp && element.startTimestamp !== 0) ||
|
||||
(element.stopTimestamp && element.stopTimestamp !== this.video.duration)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private removeVideoFromPlaylist (playlist: PlaylistSummary, elementId: number) {
|
||||
this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, elementId, this.video.id)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.notifier.success($localize`Video removed from ${playlist.displayName}`)
|
||||
|
@ -213,7 +309,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
)
|
||||
}
|
||||
|
||||
private listenToPlaylistChanges () {
|
||||
private listenToVideoPlaylistChange () {
|
||||
this.unsubscribePlaylistChanges()
|
||||
|
||||
this.listenToPlaylistChangeSub = this.videoPlaylistService.listenToVideoPlaylistChange(this.video.id)
|
||||
|
@ -231,18 +327,30 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
private rebuildPlaylists (existResult: VideoExistInPlaylist[]) {
|
||||
logger('Got existing results for %d.', this.video.id, existResult)
|
||||
|
||||
const oldPlaylists = this.videoPlaylists
|
||||
|
||||
this.videoPlaylists = []
|
||||
for (const playlist of this.playlistsData) {
|
||||
const existingPlaylist = existResult.find(p => p.playlistId === playlist.id)
|
||||
const existingPlaylists = existResult.filter(p => p.playlistId === playlist.id)
|
||||
|
||||
this.videoPlaylists.push({
|
||||
const playlistSummary = {
|
||||
id: playlist.id,
|
||||
optionalRowDisplayed: false,
|
||||
displayName: playlist.displayName,
|
||||
inPlaylist: !!existingPlaylist,
|
||||
playlistElementId: existingPlaylist ? existingPlaylist.playlistElementId : undefined,
|
||||
startTimestamp: existingPlaylist ? existingPlaylist.startTimestamp : undefined,
|
||||
stopTimestamp: existingPlaylist ? existingPlaylist.stopTimestamp : undefined
|
||||
})
|
||||
elements: existingPlaylists.map(e => ({
|
||||
enabled: true,
|
||||
playlistElementId: e.playlistElementId,
|
||||
startTimestamp: e.startTimestamp || 0,
|
||||
stopTimestamp: e.stopTimestamp || this.video.duration
|
||||
}))
|
||||
}
|
||||
|
||||
const oldPlaylist = oldPlaylists.find(p => p.id === playlist.id)
|
||||
playlistSummary.optionalRowDisplayed = oldPlaylist
|
||||
? oldPlaylist.optionalRowDisplayed
|
||||
: this.isOptionalRowDisplayed(playlistSummary)
|
||||
|
||||
this.videoPlaylists.push(playlistSummary)
|
||||
}
|
||||
|
||||
logger('Rebuilt playlist state for video %d.', this.video.id, this.videoPlaylists)
|
||||
|
@ -250,20 +358,22 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
this.cd.markForCheck()
|
||||
}
|
||||
|
||||
private addVideoInPlaylist (playlist: PlaylistSummary) {
|
||||
private addVideoInPlaylist (playlist: PlaylistSummary, element: PlaylistElement) {
|
||||
const body: VideoPlaylistElementCreate = { videoId: this.video.id }
|
||||
|
||||
if (this.timestampOptions.startTimestampEnabled) body.startTimestamp = this.timestampOptions.startTimestamp
|
||||
if (this.timestampOptions.stopTimestampEnabled) body.stopTimestamp = this.timestampOptions.stopTimestamp
|
||||
if (element.startTimestamp) body.startTimestamp = element.startTimestamp
|
||||
if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp
|
||||
|
||||
this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
|
||||
.subscribe(
|
||||
() => {
|
||||
res => {
|
||||
const message = body.startTimestamp || body.stopTimestamp
|
||||
? $localize`Video added in ${playlist.displayName} at timestamps ${this.formatTimestamp(playlist)}`
|
||||
? $localize`Video added in ${playlist.displayName} at timestamps ${this.formatTimestamp(element)}`
|
||||
: $localize`Video added in ${playlist.displayName}`
|
||||
|
||||
this.notifier.success(message)
|
||||
|
||||
if (element) element.playlistElementId = res.videoPlaylistElement.id
|
||||
},
|
||||
|
||||
err => {
|
||||
|
@ -273,4 +383,11 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
|||
() => this.cd.markForCheck()
|
||||
)
|
||||
}
|
||||
|
||||
private formatTimestamp (element: PlaylistElement) {
|
||||
const start = element.startTimestamp ? secondsToTime(element.startTimestamp) : ''
|
||||
const stop = element.stopTimestamp ? secondsToTime(element.stopTimestamp) : ''
|
||||
|
||||
return `(${start}-${stop})`
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as debug from 'debug'
|
||||
import { uniq } from 'lodash-es'
|
||||
import { asyncScheduler, merge, Observable, of, ReplaySubject, Subject } from 'rxjs'
|
||||
import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap } from 'rxjs/operators'
|
||||
import { bufferTime, catchError, filter, map, observeOn, share, switchMap, tap, distinctUntilChanged } from 'rxjs/operators'
|
||||
import { HttpClient, HttpParams } from '@angular/common/http'
|
||||
import { Injectable, NgZone } from '@angular/core'
|
||||
import { AuthUser, ComponentPaginationLight, RestExtractor, RestService, ServerService } from '@app/core'
|
||||
|
@ -53,6 +53,7 @@ export class VideoPlaylistService {
|
|||
) {
|
||||
this.videoExistsInPlaylistObservable = merge(
|
||||
this.videoExistsInPlaylistNotifier.pipe(
|
||||
distinctUntilChanged(),
|
||||
// We leave Angular zone so Protractor does not get stuck
|
||||
bufferTime(500, leaveZone(this.ngZone, asyncScheduler)),
|
||||
filter(videoIds => videoIds.length !== 0),
|
||||
|
|
Loading…
Reference in New Issue