diff --git a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts index 85c63c173..853d99ffe 100644 --- a/client/src/app/shared/shared-video-miniature/video-miniature.component.ts +++ b/client/src/app/shared/shared-video-miniature/video-miniature.component.ts @@ -88,8 +88,10 @@ export class VideoMiniatureComponent implements OnInit { channelLinkTitle = '' watchLaterPlaylist: { + displayName: string id: number playlistElementId?: number + shortUUID: string } videoRouterLink: string | any[] = [] @@ -245,7 +247,7 @@ export class VideoMiniatureComponent implements OnInit { addToWatchLater () { const body = { videoId: this.video.id } - this.videoPlaylistService.addVideoInPlaylist(this.watchLaterPlaylist.id, body) + this.videoPlaylistService.addVideoInPlaylist(this.watchLaterPlaylist, body) .subscribe( res => { this.watchLaterPlaylist.playlistElementId = res.videoPlaylistElement.id @@ -303,7 +305,9 @@ export class VideoMiniatureComponent implements OnInit { this.inWatchLaterPlaylist = false this.watchLaterPlaylist = { - id: watchLaterPlaylist.id + id: watchLaterPlaylist.id, + displayName: watchLaterPlaylist.name, + shortUUID: watchLaterPlaylist.shortUUID } if (existsInWatchLater) { diff --git a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts index e019fdd26..f71b95bbb 100644 --- a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts +++ b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts @@ -6,6 +6,7 @@ import { AuthService, DisableForReuseHook, Notifier } from '@app/core' import { FormReactive, FormValidatorService } from '@app/shared/shared-forms' import { secondsToTime } from '@shared/core-utils' import { + VideoPlaylistSummary, Video, VideoExistInPlaylist, VideoPlaylistCreate, @@ -25,11 +26,8 @@ type PlaylistElement = { stopTimestamp?: number } -type PlaylistSummary = { - id: number - displayName: string +type PlaylistSummaryWithElements = VideoPlaylistSummary & { optionalRowDisplayed: boolean - elements: PlaylistElement[] } @@ -49,7 +47,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, videoPlaylistSearch: string videoPlaylistSearchChanged = new Subject() - videoPlaylists: PlaylistSummary[] = [] + videoPlaylists: PlaylistSummaryWithElements[] = [] private disabled = false @@ -145,7 +143,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, this.isNewPlaylistBlockOpened = true } - toggleMainPlaylist (e: Event, playlist: PlaylistSummary) { + toggleMainPlaylist (e: Event, playlist: PlaylistSummaryWithElements) { e.preventDefault() if (this.isPresentMultipleTimes(playlist) || playlist.optionalRowDisplayed) return @@ -167,7 +165,13 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, this.cd.markForCheck() } - toggleOptionalPlaylist (e: Event, playlist: PlaylistSummary, element: PlaylistElement, startTimestamp: number, stopTimestamp: number) { + toggleOptionalPlaylist ( + e: Event, + playlist: PlaylistSummaryWithElements, + element: PlaylistElement, + startTimestamp: number, + stopTimestamp: number + ) { e.preventDefault() if (element.enabled) { @@ -216,23 +220,23 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, this.videoPlaylistSearchChanged.next() } - isPrimaryCheckboxChecked (playlist: PlaylistSummary) { + isPrimaryCheckboxChecked (playlist: PlaylistSummaryWithElements) { // Reduce latency when adding a video to a playlist using pendingAddId return this.pendingAddId === playlist.id || playlist.elements.filter(e => e.enabled).length !== 0 } - toggleOptionalRow (playlist: PlaylistSummary) { + toggleOptionalRow (playlist: PlaylistSummaryWithElements) { playlist.optionalRowDisplayed = !playlist.optionalRowDisplayed this.cd.markForCheck() } - getPrimaryInputName (playlist: PlaylistSummary) { + getPrimaryInputName (playlist: PlaylistSummaryWithElements) { return 'in-playlist-primary-' + playlist.id } - getOptionalInputName (playlist: PlaylistSummary, element?: PlaylistElement) { + getOptionalInputName (playlist: PlaylistSummaryWithElements, element?: PlaylistElement) { const suffix = element ? '-' + element.playlistElementId : '' @@ -240,7 +244,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, return 'in-playlist-optional-' + playlist.id + suffix } - buildOptionalRowElements (playlist: PlaylistSummary) { + buildOptionalRowElements (playlist: PlaylistSummaryWithElements) { const elements = playlist.elements const lastElement = elements.length === 0 @@ -259,11 +263,11 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, return elements } - isPresentMultipleTimes (playlist: PlaylistSummary) { + isPresentMultipleTimes (playlist: PlaylistSummaryWithElements) { return playlist.elements.filter(e => e.enabled === true).length > 1 } - onElementTimestampUpdate (playlist: PlaylistSummary, element: PlaylistElement) { + onElementTimestampUpdate (playlist: PlaylistSummaryWithElements, element: PlaylistElement) { if (!element.playlistElementId || element.enabled === false) return const body: VideoPlaylistElementUpdate = { @@ -283,7 +287,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, }) } - private isOptionalRowDisplayed (playlist: PlaylistSummary) { + private isOptionalRowDisplayed (playlist: PlaylistSummaryWithElements) { const elements = playlist.elements.filter(e => e.enabled) if (elements.length > 1) return true @@ -302,7 +306,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, return false } - private removeVideoFromPlaylist (playlist: PlaylistSummary, elementId: number) { + private removeVideoFromPlaylist (playlist: PlaylistSummaryWithElements, elementId: number) { this.videoPlaylistService.removeVideoFromPlaylist(playlist.id, elementId, this.video.id) .subscribe({ next: () => { @@ -348,7 +352,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, playlistElementId: e.playlistElementId, startTimestamp: e.startTimestamp || 0, stopTimestamp: e.stopTimestamp || this.video.duration - })) + })), + shortUUID: playlist.shortUUID } const oldPlaylist = oldPlaylists.find(p => p.id === playlist.id) @@ -364,7 +369,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, this.cd.markForCheck() } - private addVideoInPlaylist (playlist: PlaylistSummary, element: PlaylistElement) { + private addVideoInPlaylist (playlist: PlaylistSummaryWithElements, element: PlaylistElement) { const body: VideoPlaylistElementCreate = { videoId: this.video.id } if (element.startTimestamp) body.startTimestamp = element.startTimestamp @@ -372,7 +377,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, this.pendingAddId = playlist.id - this.videoPlaylistService.addVideoInPlaylist(playlist.id, body) + this.videoPlaylistService.addVideoInPlaylist(playlist, body) .subscribe({ next: res => { const message = body.startTimestamp || body.stopTimestamp diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.service.ts b/client/src/app/shared/shared-video-playlist/video-playlist.service.ts index 880890580..09b275ecd 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist.service.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist.service.ts @@ -8,6 +8,7 @@ import { buildBulkObservable, objectToFormData } from '@app/helpers' import { Account, AccountService, VideoChannel, VideoChannelService } from '@app/shared/shared-main' import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client' import { + VideoPlaylistSummary, ResultList, VideoExistInPlaylist, VideoPlaylist as VideoPlaylistServerModel, @@ -17,7 +18,8 @@ import { VideoPlaylistElementUpdate, VideoPlaylistReorder, VideoPlaylistUpdate, - VideosExistInPlaylists + VideosExistInPlaylists, + VideoPlaylistCreateResult } from '@shared/models' import { environment } from '../../../environments/environment' import { VideoPlaylistElement } from './video-playlist-element.model' @@ -25,7 +27,7 @@ import { VideoPlaylist } from './video-playlist.model' const debugLogger = debug('peertube:playlists:VideoPlaylistService') -export type CachedPlaylist = VideoPlaylist | { id: number, displayName: string } +export type CachedPlaylist = VideoPlaylist | VideoPlaylistSummary @Injectable() export class VideoPlaylistService { @@ -139,7 +141,7 @@ export class VideoPlaylistService { createVideoPlaylist (body: VideoPlaylistCreate) { const data = objectToFormData(body) - return this.authHttp.post<{ videoPlaylist: { id: number } }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data) + return this.authHttp.post<{ videoPlaylist: VideoPlaylistCreateResult }>(VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL, data) .pipe( tap(res => { if (!this.myAccountPlaylistCache) return @@ -148,7 +150,8 @@ export class VideoPlaylistService { this.myAccountPlaylistCache.data.push({ id: res.videoPlaylist.id, - displayName: body.displayName + displayName: body.displayName, + shortUUID: res.videoPlaylist.shortUUID }) this.myAccountPlaylistCacheSubject.next(this.myAccountPlaylistCache) @@ -190,12 +193,23 @@ export class VideoPlaylistService { ) } - addVideoInPlaylist (playlistId: number, body: VideoPlaylistElementCreate) { - const url = VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlistId + '/videos' + addVideoInPlaylist (playlist: VideoPlaylistSummary, body: VideoPlaylistElementCreate) { + const url = VideoPlaylistService.BASE_VIDEO_PLAYLIST_URL + playlist.id + '/videos' return this.authHttp.post<{ videoPlaylistElement: { id: number } }>(url, body) .pipe( tap(res => { + const existsResult = this.videoExistsCache[body.videoId] + + existsResult.push({ + playlistElementId: res.videoPlaylistElement.id, + playlistId: playlist.id, + playlistDisplayName: playlist.displayName, + playlistShortUUID: playlist.shortUUID, + startTimestamp: body.startTimestamp, + stopTimestamp: body.stopTimestamp + }) + this.runPlaylistCheck(body.videoId) }), catchError(err => this.restExtractor.handleError(err)) diff --git a/server/models/user/user.ts b/server/models/user/user.ts index 1a7c84390..05f9c0a6b 100644 --- a/server/models/user/user.ts +++ b/server/models/user/user.ts @@ -70,6 +70,7 @@ import { VideoImportModel } from '../video/video-import' import { VideoLiveModel } from '../video/video-live' import { VideoPlaylistModel } from '../video/video-playlist' import { UserNotificationSettingModel } from './user-notification-setting' +import { uuidToShort } from '@shared/extra-utils' enum ScopeNames { FOR_ME_API = 'FOR_ME_API', @@ -960,7 +961,7 @@ export class UserModel extends Model>> { const formatted = this.toFormattedJSON({ withAdminFlags: true }) const specialPlaylists = this.Account.VideoPlaylists - .map(p => ({ id: p.id, name: p.name, type: p.type })) + .map(p => ({ id: p.id, name: p.name, shortUUID: uuidToShort(p.uuid), type: p.type })) return Object.assign(formatted, { specialPlaylists }) } diff --git a/shared/models/users/user.model.ts b/shared/models/users/user.model.ts index 63c5c8a92..19dc3c068 100644 --- a/shared/models/users/user.model.ts +++ b/shared/models/users/user.model.ts @@ -67,6 +67,7 @@ export interface User { export interface MyUserSpecialPlaylist { id: number name: string + shortUUID: string type: VideoPlaylistType } diff --git a/shared/models/videos/playlist/video-exist-in-playlist.model.ts b/shared/models/videos/playlist/video-exist-in-playlist.model.ts index c29b1ee38..dd3e8439e 100644 --- a/shared/models/videos/playlist/video-exist-in-playlist.model.ts +++ b/shared/models/videos/playlist/video-exist-in-playlist.model.ts @@ -10,3 +10,9 @@ export type VideoExistInPlaylist = { startTimestamp?: number stopTimestamp?: number } + +export type VideoPlaylistSummary = { + id: number + displayName: string + shortUUID: string +}