feat: show contained playlists under My videos (#5125)
* feat: show contained playlists under My videos closes #4769 * refactor(server): remove unused types * fixes after code review * fix(client/video-miniature): add to playlist * fix(server/user/me): shortUUID response * Revert "fix(client/video-miniature): add to playlist" This reverts commitf1a0412391
. * fix(client/PlaylistService): caching * Revert "fix(server/user/me): shortUUID response" This reverts commite3f1ee4e33
. * Fix fetching playlists Co-authored-by: Chocobozzz <me@florianbigard.com>
This commit is contained in:
parent
01a3c07a79
commit
38a3ccc7f8
|
@ -34,6 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-videos-selection
|
<my-videos-selection
|
||||||
|
[videosContainedInPlaylists]="videosContainedInPlaylists"
|
||||||
[pagination]="pagination"
|
[pagination]="pagination"
|
||||||
[(selection)]="selection"
|
[(selection)]="selection"
|
||||||
[(videosModel)]="videos"
|
[(videosModel)]="videos"
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
import { uniqBy } from 'lodash'
|
||||||
import { concat, Observable } from 'rxjs'
|
import { concat, Observable } from 'rxjs'
|
||||||
import { tap, toArray } from 'rxjs/operators'
|
import { tap, toArray } from 'rxjs/operators'
|
||||||
import { Component, OnInit, ViewChild } from '@angular/core'
|
import { Component, OnInit, ViewChild } from '@angular/core'
|
||||||
import { ActivatedRoute, Router } from '@angular/router'
|
import { ActivatedRoute, Router } from '@angular/router'
|
||||||
import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core'
|
import { AuthService, ComponentPagination, ConfirmService, Notifier, ScreenService, ServerService, User } from '@app/core'
|
||||||
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
|
import { DisableForReuseHook } from '@app/core/routing/disable-for-reuse-hook'
|
||||||
import { prepareIcu, immutableAssign } from '@app/helpers'
|
import { immutableAssign, prepareIcu } from '@app/helpers'
|
||||||
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||||
import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
|
import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
|
||||||
import { LiveStreamInformationComponent } from '@app/shared/shared-video-live'
|
import { LiveStreamInformationComponent } from '@app/shared/shared-video-live'
|
||||||
|
@ -14,7 +15,8 @@ import {
|
||||||
VideoActionsDisplayType,
|
VideoActionsDisplayType,
|
||||||
VideosSelectionComponent
|
VideosSelectionComponent
|
||||||
} from '@app/shared/shared-video-miniature'
|
} from '@app/shared/shared-video-miniature'
|
||||||
import { VideoChannel, VideoSortField } from '@shared/models'
|
import { VideoPlaylistService } from '@app/shared/shared-video-playlist'
|
||||||
|
import { VideoChannel, VideoExistInPlaylist, VideosExistInPlaylists, VideoSortField } from '@shared/models'
|
||||||
import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component'
|
import { VideoChangeOwnershipComponent } from './modals/video-change-ownership.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -26,6 +28,7 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
|
||||||
@ViewChild('videoChangeOwnershipModal', { static: true }) videoChangeOwnershipModal: VideoChangeOwnershipComponent
|
@ViewChild('videoChangeOwnershipModal', { static: true }) videoChangeOwnershipModal: VideoChangeOwnershipComponent
|
||||||
@ViewChild('liveStreamInformationModal', { static: true }) liveStreamInformationModal: LiveStreamInformationComponent
|
@ViewChild('liveStreamInformationModal', { static: true }) liveStreamInformationModal: LiveStreamInformationComponent
|
||||||
|
|
||||||
|
videosContainedInPlaylists: VideosExistInPlaylists = {}
|
||||||
titlePage: string
|
titlePage: string
|
||||||
selection: SelectionType = {}
|
selection: SelectionType = {}
|
||||||
pagination: ComponentPagination = {
|
pagination: ComponentPagination = {
|
||||||
|
@ -83,7 +86,8 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
|
||||||
protected notifier: Notifier,
|
protected notifier: Notifier,
|
||||||
protected screenService: ScreenService,
|
protected screenService: ScreenService,
|
||||||
private confirmService: ConfirmService,
|
private confirmService: ConfirmService,
|
||||||
private videoService: VideoService
|
private videoService: VideoService,
|
||||||
|
private playlistService: VideoPlaylistService
|
||||||
) {
|
) {
|
||||||
this.titlePage = $localize`My videos`
|
this.titlePage = $localize`My videos`
|
||||||
}
|
}
|
||||||
|
@ -156,10 +160,20 @@ export class MyVideosComponent implements OnInit, DisableForReuseHook {
|
||||||
sort: this.sort,
|
sort: this.sort,
|
||||||
userChannels: this.userChannels,
|
userChannels: this.userChannels,
|
||||||
search: this.search
|
search: this.search
|
||||||
})
|
}).pipe(
|
||||||
.pipe(
|
tap(res => this.pagination.totalItems = res.total),
|
||||||
tap(res => this.pagination.totalItems = res.total)
|
tap(({ data }) => this.fetchVideosContainedInPlaylists(data))
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchVideosContainedInPlaylists (videos: Video[]) {
|
||||||
|
this.playlistService.doVideosExistInPlaylist(videos.map(v => v.id))
|
||||||
|
.subscribe(result => {
|
||||||
|
this.videosContainedInPlaylists = Object.keys(result).reduce((acc, videoId) => ({
|
||||||
|
...acc,
|
||||||
|
[videoId]: uniqBy(result[videoId], (p: VideoExistInPlaylist) => p.playlistId)
|
||||||
|
}), this.videosContainedInPlaylists)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteSelectedVideos () {
|
async deleteSelectedVideos () {
|
||||||
|
|
|
@ -52,6 +52,12 @@
|
||||||
<ng-container *ngIf="displayOptions.privacyText && displayOptions.state && getStateLabel(video)"> - </ng-container>
|
<ng-container *ngIf="displayOptions.privacyText && displayOptions.state && getStateLabel(video)"> - </ng-container>
|
||||||
<ng-container *ngIf="displayOptions.state">{{ getStateLabel(video) }}</ng-container>
|
<ng-container *ngIf="displayOptions.state">{{ getStateLabel(video) }}</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="containedInPlaylists" class="video-contained-in-playlists">
|
||||||
|
<a *ngFor="let playlist of containedInPlaylists" class="chip rectangular bg-secondary text-light" [routerLink]="['/w/p/', playlist.playlistShortUUID]">
|
||||||
|
{{ playlist.playlistDisplayName }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
$more-button-width: 40px;
|
$more-button-width: 40px;
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
@include chip;
|
||||||
|
}
|
||||||
|
|
||||||
.video-miniature {
|
.video-miniature {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
Output
|
Output
|
||||||
} from '@angular/core'
|
} from '@angular/core'
|
||||||
import { AuthService, ScreenService, ServerService, User } from '@app/core'
|
import { AuthService, ScreenService, ServerService, User } from '@app/core'
|
||||||
import { HTMLServerConfig, VideoPlaylistType, VideoPrivacy, VideoState } from '@shared/models'
|
import { HTMLServerConfig, VideoExistInPlaylist, VideoPlaylistType, VideoPrivacy, VideoState } from '@shared/models'
|
||||||
import { LinkType } from '../../../types/link.type'
|
import { LinkType } from '../../../types/link.type'
|
||||||
import { ActorAvatarSize } from '../shared-actor-image/actor-avatar.component'
|
import { ActorAvatarSize } from '../shared-actor-image/actor-avatar.component'
|
||||||
import { Video } from '../shared-main'
|
import { Video } from '../shared-main'
|
||||||
|
@ -40,6 +40,7 @@ export type MiniatureDisplayOptions = {
|
||||||
export class VideoMiniatureComponent implements OnInit {
|
export class VideoMiniatureComponent implements OnInit {
|
||||||
@Input() user: User
|
@Input() user: User
|
||||||
@Input() video: Video
|
@Input() video: Video
|
||||||
|
@Input() containedInPlaylists: VideoExistInPlaylist[]
|
||||||
|
|
||||||
@Input() displayOptions: MiniatureDisplayOptions = {
|
@Input() displayOptions: MiniatureDisplayOptions = {
|
||||||
date: true,
|
date: true,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<my-video-miniature
|
<my-video-miniature
|
||||||
|
[containedInPlaylists]="videosContainedInPlaylists ? videosContainedInPlaylists[video.id] : undefined"
|
||||||
[video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions"
|
[video]="video" [displayAsRow]="true" [displayOptions]="miniatureDisplayOptions"
|
||||||
[displayVideoActions]="false" [user]="user"
|
[displayVideoActions]="false" [user]="user"
|
||||||
></my-video-miniature>
|
></my-video-miniature>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { Observable, Subject } from 'rxjs'
|
||||||
import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core'
|
import { AfterContentInit, Component, ContentChildren, EventEmitter, Input, Output, QueryList, TemplateRef } from '@angular/core'
|
||||||
import { ComponentPagination, Notifier, User } from '@app/core'
|
import { ComponentPagination, Notifier, User } from '@app/core'
|
||||||
import { logger } from '@root-helpers/logger'
|
import { logger } from '@root-helpers/logger'
|
||||||
import { ResultList, VideoSortField } from '@shared/models'
|
import { ResultList, VideosExistInPlaylists, VideoSortField } from '@shared/models'
|
||||||
import { PeerTubeTemplateDirective, Video } from '../shared-main'
|
import { PeerTubeTemplateDirective, Video } from '../shared-main'
|
||||||
import { MiniatureDisplayOptions } from './video-miniature.component'
|
import { MiniatureDisplayOptions } from './video-miniature.component'
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@ export type SelectionType = { [ id: number ]: boolean }
|
||||||
styleUrls: [ './videos-selection.component.scss' ]
|
styleUrls: [ './videos-selection.component.scss' ]
|
||||||
})
|
})
|
||||||
export class VideosSelectionComponent implements AfterContentInit {
|
export class VideosSelectionComponent implements AfterContentInit {
|
||||||
|
@Input() videosContainedInPlaylists: VideosExistInPlaylists
|
||||||
@Input() user: User
|
@Input() user: User
|
||||||
@Input() pagination: ComponentPagination
|
@Input() pagination: ComponentPagination
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,8 @@ import { AuthService, DisableForReuseHook, Notifier } from '@app/core'
|
||||||
import { FormReactive, FormReactiveService } from '@app/shared/shared-forms'
|
import { FormReactive, FormReactiveService } from '@app/shared/shared-forms'
|
||||||
import { secondsToTime } from '@shared/core-utils'
|
import { secondsToTime } from '@shared/core-utils'
|
||||||
import {
|
import {
|
||||||
|
CachedVideoExistInPlaylist,
|
||||||
Video,
|
Video,
|
||||||
VideoExistInPlaylist,
|
|
||||||
VideoPlaylistCreate,
|
VideoPlaylistCreate,
|
||||||
VideoPlaylistElementCreate,
|
VideoPlaylistElementCreate,
|
||||||
VideoPlaylistElementUpdate,
|
VideoPlaylistElementUpdate,
|
||||||
|
@ -330,7 +330,7 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private rebuildPlaylists (existResult: VideoExistInPlaylist[]) {
|
private rebuildPlaylists (existResult: CachedVideoExistInPlaylist[]) {
|
||||||
debugLogger('Got existing results for %d.', this.video.id, existResult)
|
debugLogger('Got existing results for %d.', this.video.id, existResult)
|
||||||
|
|
||||||
const oldPlaylists = this.videoPlaylists
|
const oldPlaylists = this.videoPlaylists
|
||||||
|
|
|
@ -8,6 +8,8 @@ import { buildBulkObservable, objectToFormData } from '@app/helpers'
|
||||||
import { Account, AccountService, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
import { Account, AccountService, VideoChannel, VideoChannelService } from '@app/shared/shared-main'
|
||||||
import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client'
|
import { NGX_LOADING_BAR_IGNORED } from '@ngx-loading-bar/http-client'
|
||||||
import {
|
import {
|
||||||
|
CachedVideoExistInPlaylist,
|
||||||
|
CachedVideosExistInPlaylists,
|
||||||
ResultList,
|
ResultList,
|
||||||
VideoExistInPlaylist,
|
VideoExistInPlaylist,
|
||||||
VideoPlaylist as VideoPlaylistServerModel,
|
VideoPlaylist as VideoPlaylistServerModel,
|
||||||
|
@ -34,11 +36,11 @@ export class VideoPlaylistService {
|
||||||
|
|
||||||
// Use a replay subject because we "next" a value before subscribing
|
// Use a replay subject because we "next" a value before subscribing
|
||||||
private videoExistsInPlaylistNotifier = new ReplaySubject<number>(1)
|
private videoExistsInPlaylistNotifier = new ReplaySubject<number>(1)
|
||||||
private videoExistsInPlaylistCacheSubject = new Subject<VideosExistInPlaylists>()
|
private videoExistsInPlaylistCacheSubject = new Subject<CachedVideosExistInPlaylists>()
|
||||||
private readonly videoExistsInPlaylistObservable: Observable<VideosExistInPlaylists>
|
private readonly videoExistsInPlaylistObservable: Observable<CachedVideosExistInPlaylists>
|
||||||
|
|
||||||
private videoExistsObservableCache: { [ id: number ]: Observable<VideoExistInPlaylist[]> } = {}
|
private videoExistsObservableCache: { [ id: number ]: Observable<CachedVideoExistInPlaylist[]> } = {}
|
||||||
private videoExistsCache: { [ id: number ]: VideoExistInPlaylist[] } = {}
|
private videoExistsCache: { [ id: number ]: CachedVideoExistInPlaylist[] } = {}
|
||||||
|
|
||||||
private myAccountPlaylistCache: ResultList<CachedPlaylist> = undefined
|
private myAccountPlaylistCache: ResultList<CachedPlaylist> = undefined
|
||||||
private myAccountPlaylistCacheRunning: Observable<ResultList<CachedPlaylist>>
|
private myAccountPlaylistCacheRunning: Observable<ResultList<CachedPlaylist>>
|
||||||
|
@ -346,7 +348,7 @@ export class VideoPlaylistService {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private doVideosExistInPlaylist (videoIds: number[]): Observable<VideosExistInPlaylists> {
|
doVideosExistInPlaylist (videoIds: number[]): Observable<VideosExistInPlaylists> {
|
||||||
const url = VideoPlaylistService.MY_VIDEO_PLAYLIST_URL + 'videos-exist'
|
const url = VideoPlaylistService.MY_VIDEO_PLAYLIST_URL + 'videos-exist'
|
||||||
|
|
||||||
let params = new HttpParams()
|
let params = new HttpParams()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { uuidToShort } from '@shared/extra-utils'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { VideosExistInPlaylists } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
|
import { VideosExistInPlaylists } from '../../../../shared/models/videos/playlist/video-exist-in-playlist.model'
|
||||||
import { asyncMiddleware, authenticate } from '../../../middlewares'
|
import { asyncMiddleware, authenticate } from '../../../middlewares'
|
||||||
|
@ -24,7 +25,7 @@ async function doVideosInPlaylistExist (req: express.Request, res: express.Respo
|
||||||
const videoIds = req.query.videoIds.map(i => parseInt(i + '', 10))
|
const videoIds = req.query.videoIds.map(i => parseInt(i + '', 10))
|
||||||
const user = res.locals.oauth.token.User
|
const user = res.locals.oauth.token.User
|
||||||
|
|
||||||
const results = await VideoPlaylistModel.listPlaylistIdsOf(user.Account.id, videoIds)
|
const results = await VideoPlaylistModel.listPlaylistSummariesOf(user.Account.id, videoIds)
|
||||||
|
|
||||||
const existObject: VideosExistInPlaylists = {}
|
const existObject: VideosExistInPlaylists = {}
|
||||||
|
|
||||||
|
@ -37,6 +38,8 @@ async function doVideosInPlaylistExist (req: express.Request, res: express.Respo
|
||||||
existObject[element.videoId].push({
|
existObject[element.videoId].push({
|
||||||
playlistElementId: element.id,
|
playlistElementId: element.id,
|
||||||
playlistId: result.id,
|
playlistId: result.id,
|
||||||
|
playlistDisplayName: result.name,
|
||||||
|
playlistShortUUID: uuidToShort(result.uuid),
|
||||||
startTimestamp: element.startTimestamp,
|
startTimestamp: element.startTimestamp,
|
||||||
stopTimestamp: element.stopTimestamp
|
stopTimestamp: element.stopTimestamp
|
||||||
})
|
})
|
||||||
|
|
|
@ -49,7 +49,7 @@ import {
|
||||||
MVideoPlaylistFormattable,
|
MVideoPlaylistFormattable,
|
||||||
MVideoPlaylistFull,
|
MVideoPlaylistFull,
|
||||||
MVideoPlaylistFullSummary,
|
MVideoPlaylistFullSummary,
|
||||||
MVideoPlaylistIdWithElements
|
MVideoPlaylistSummaryWithElements
|
||||||
} from '../../types/models/video/video-playlist'
|
} from '../../types/models/video/video-playlist'
|
||||||
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account'
|
import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account'
|
||||||
import { ActorModel } from '../actor/actor'
|
import { ActorModel } from '../actor/actor'
|
||||||
|
@ -470,9 +470,9 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
static listPlaylistIdsOf (accountId: number, videoIds: number[]): Promise<MVideoPlaylistIdWithElements[]> {
|
static listPlaylistSummariesOf (accountId: number, videoIds: number[]): Promise<MVideoPlaylistSummaryWithElements[]> {
|
||||||
const query = {
|
const query = {
|
||||||
attributes: [ 'id' ],
|
attributes: [ 'id', 'name', 'uuid' ],
|
||||||
where: {
|
where: {
|
||||||
ownerAccountId: accountId
|
ownerAccountId: accountId
|
||||||
},
|
},
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
setDefaultVideoChannel,
|
setDefaultVideoChannel,
|
||||||
waitJobs
|
waitJobs
|
||||||
} from '@shared/server-commands'
|
} from '@shared/server-commands'
|
||||||
|
import { uuidToShort } from '@shared/extra-utils'
|
||||||
|
|
||||||
async function checkPlaylistElementType (
|
async function checkPlaylistElementType (
|
||||||
servers: PeerTubeServer[],
|
servers: PeerTubeServer[],
|
||||||
|
@ -56,6 +57,7 @@ describe('Test video playlists', function () {
|
||||||
let playlistServer2UUID2: string
|
let playlistServer2UUID2: string
|
||||||
|
|
||||||
let playlistServer1Id: number
|
let playlistServer1Id: number
|
||||||
|
let playlistServer1DisplayName: string
|
||||||
let playlistServer1UUID: string
|
let playlistServer1UUID: string
|
||||||
let playlistServer1UUID2: string
|
let playlistServer1UUID2: string
|
||||||
|
|
||||||
|
@ -489,15 +491,17 @@ describe('Test video playlists', function () {
|
||||||
return commands[0].addElement({ playlistId: playlistServer1Id, attributes })
|
return commands[0].addElement({ playlistId: playlistServer1Id, attributes })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const playlistDisplayName = 'playlist 4'
|
||||||
const playlist = await commands[0].create({
|
const playlist = await commands[0].create({
|
||||||
attributes: {
|
attributes: {
|
||||||
displayName: 'playlist 4',
|
displayName: playlistDisplayName,
|
||||||
privacy: VideoPlaylistPrivacy.PUBLIC,
|
privacy: VideoPlaylistPrivacy.PUBLIC,
|
||||||
videoChannelId: servers[0].store.channel.id
|
videoChannelId: servers[0].store.channel.id
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
playlistServer1Id = playlist.id
|
playlistServer1Id = playlist.id
|
||||||
|
playlistServer1DisplayName = playlistDisplayName
|
||||||
playlistServer1UUID = playlist.uuid
|
playlistServer1UUID = playlist.uuid
|
||||||
|
|
||||||
await addVideo({ videoId: servers[0].store.videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
|
await addVideo({ videoId: servers[0].store.videos[0].uuid, startTimestamp: 15, stopTimestamp: 28 })
|
||||||
|
@ -908,6 +912,8 @@ describe('Test video playlists', function () {
|
||||||
const elem = obj[servers[0].store.videos[0].id]
|
const elem = obj[servers[0].store.videos[0].id]
|
||||||
expect(elem).to.have.lengthOf(1)
|
expect(elem).to.have.lengthOf(1)
|
||||||
expect(elem[0].playlistElementId).to.exist
|
expect(elem[0].playlistElementId).to.exist
|
||||||
|
expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName)
|
||||||
|
expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID))
|
||||||
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
||||||
expect(elem[0].startTimestamp).to.equal(15)
|
expect(elem[0].startTimestamp).to.equal(15)
|
||||||
expect(elem[0].stopTimestamp).to.equal(28)
|
expect(elem[0].stopTimestamp).to.equal(28)
|
||||||
|
@ -917,6 +923,8 @@ describe('Test video playlists', function () {
|
||||||
const elem = obj[servers[0].store.videos[3].id]
|
const elem = obj[servers[0].store.videos[3].id]
|
||||||
expect(elem).to.have.lengthOf(1)
|
expect(elem).to.have.lengthOf(1)
|
||||||
expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
|
expect(elem[0].playlistElementId).to.equal(playlistElementServer1Video4)
|
||||||
|
expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName)
|
||||||
|
expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID))
|
||||||
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
||||||
expect(elem[0].startTimestamp).to.equal(1)
|
expect(elem[0].startTimestamp).to.equal(1)
|
||||||
expect(elem[0].stopTimestamp).to.equal(35)
|
expect(elem[0].stopTimestamp).to.equal(35)
|
||||||
|
@ -926,6 +934,8 @@ describe('Test video playlists', function () {
|
||||||
const elem = obj[servers[0].store.videos[4].id]
|
const elem = obj[servers[0].store.videos[4].id]
|
||||||
expect(elem).to.have.lengthOf(1)
|
expect(elem).to.have.lengthOf(1)
|
||||||
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
expect(elem[0].playlistId).to.equal(playlistServer1Id)
|
||||||
|
expect(elem[0].playlistDisplayName).to.equal(playlistServer1DisplayName)
|
||||||
|
expect(elem[0].playlistShortUUID).to.equal(uuidToShort(playlistServer1UUID))
|
||||||
expect(elem[0].startTimestamp).to.equal(45)
|
expect(elem[0].startTimestamp).to.equal(45)
|
||||||
expect(elem[0].stopTimestamp).to.equal(null)
|
expect(elem[0].stopTimestamp).to.equal(null)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,10 @@ export type MVideoPlaylist = Omit<VideoPlaylistModel, 'OwnerAccount' | 'VideoCha
|
||||||
// ############################################################################
|
// ############################################################################
|
||||||
|
|
||||||
export type MVideoPlaylistId = Pick<MVideoPlaylist, 'id'>
|
export type MVideoPlaylistId = Pick<MVideoPlaylist, 'id'>
|
||||||
|
export type MVideoPlaylistSummary =
|
||||||
|
Pick<MVideoPlaylist, 'id'> &
|
||||||
|
Pick<MVideoPlaylist, 'name'> &
|
||||||
|
Pick<MVideoPlaylist, 'uuid'>
|
||||||
export type MVideoPlaylistPrivacy = Pick<MVideoPlaylist, 'privacy'>
|
export type MVideoPlaylistPrivacy = Pick<MVideoPlaylist, 'privacy'>
|
||||||
export type MVideoPlaylistUUID = Pick<MVideoPlaylist, 'uuid'>
|
export type MVideoPlaylistUUID = Pick<MVideoPlaylist, 'uuid'>
|
||||||
export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: number }
|
export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: number }
|
||||||
|
@ -22,12 +26,8 @@ export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: numbe
|
||||||
|
|
||||||
// With elements
|
// With elements
|
||||||
|
|
||||||
export type MVideoPlaylistWithElements =
|
export type MVideoPlaylistSummaryWithElements =
|
||||||
MVideoPlaylist &
|
MVideoPlaylistSummary &
|
||||||
Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
|
|
||||||
|
|
||||||
export type MVideoPlaylistIdWithElements =
|
|
||||||
MVideoPlaylistId &
|
|
||||||
Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
|
Use<'VideoPlaylistElements', MVideoPlaylistElementLight[]>
|
||||||
|
|
||||||
// ############################################################################
|
// ############################################################################
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
export type VideosExistInPlaylists = {
|
export type VideosExistInPlaylists = {
|
||||||
[videoId: number ]: VideoExistInPlaylist[]
|
[videoId: number ]: VideoExistInPlaylist[]
|
||||||
}
|
}
|
||||||
|
export type CachedVideosExistInPlaylists = {
|
||||||
|
[videoId: number ]: CachedVideoExistInPlaylist[]
|
||||||
|
}
|
||||||
|
|
||||||
export type VideoExistInPlaylist = {
|
export type CachedVideoExistInPlaylist = {
|
||||||
playlistElementId: number
|
playlistElementId: number
|
||||||
playlistId: number
|
playlistId: number
|
||||||
startTimestamp?: number
|
startTimestamp?: number
|
||||||
stopTimestamp?: number
|
stopTimestamp?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type VideoExistInPlaylist = CachedVideoExistInPlaylist & {
|
||||||
|
playlistDisplayName: string
|
||||||
|
playlistShortUUID: string
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user