<span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span>
- <span *ngIf="isUnpublished(video.state.id)" class="badge badge-yellow" i18n>Not published yet</span>
+ <span *ngIf="isUnpublished(video.state.id)" class="badge badge-yellow" i18n>{{ video.state.label }}</span>
<span *ngIf="isAccountBlocked(video)" class="badge badge-red" i18n>Account muted</span>
<span *ngIf="isServerBlocked(video)" class="badge badge-red" i18n>Server muted</span>
<td>
<span *ngIf="isHLS(video)" class="badge badge-blue">HLS</span>
<span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent</span>
+ <span *ngIf="video.isLive" class="badge badge-blue">Live</span>
- <span *ngIf="!video.remote">{{ getFilesSize(video) | bytes: 1 }}</span>
+ <span *ngIf="!video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span>
</td>
<td>
videos: Video[] = []
totalRecords = 0
- sort: SortMeta = { field: 'publishedAt', order: 1 }
+ sort: SortMeta = { field: 'publishedAt', order: -1 }
pagination: RestPagination = { count: this.rowsPerPage, start: 0 }
bulkVideoActions: DropdownAction<Video[]>[][] = []
}
isUnpublished (state: VideoState) {
- return state !== VideoState.PUBLISHED
+ return state !== VideoState.LIVE_ENDED && state !== VideoState.PUBLISHED
}
isAccountBlocked (video: Video) {
@Injectable()
export class VideoService {
- static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
+ static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos'
static BASE_FEEDS_URL = environment.apiUrl + '/feeds/videos.'
static BASE_SUBSCRIPTION_FEEDS_URL = environment.apiUrl + '/feeds/subscriptions.'
) {}
getVideoViewUrl (uuid: string) {
- return VideoService.BASE_VIDEO_URL + uuid + '/views'
+ return VideoService.BASE_VIDEO_URL + '/' + uuid + '/views'
}
getUserWatchingVideoUrl (uuid: string) {
- return VideoService.BASE_VIDEO_URL + uuid + '/watching'
+ return VideoService.BASE_VIDEO_URL + '/' + uuid + '/watching'
}
getVideo (options: { videoId: string }): Observable<VideoDetails> {
return this.serverService.getServerLocale()
.pipe(
switchMap(translations => {
- return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + options.videoId)
+ return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + '/' + options.videoId)
.pipe(map(videoHash => ({ videoHash, translations })))
}),
map(({ videoHash, translations }) => new VideoDetails(videoHash, translations)),
const data = objectToFormData(body)
- return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data)
+ return this.authHttp.put(VideoService.BASE_VIDEO_URL + '/' + video.id, data)
.pipe(
map(this.restExtractor.extractDataBool),
catchError(err => this.restExtractor.handleError(err))
}
uploadVideo (video: FormData) {
- const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
+ const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + '/' + 'upload', video, { reportProgress: true })
return this.authHttp
.request<{ video: { id: number, uuid: string } }>(req)
return from(ids)
.pipe(
- concatMap(id => this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)),
+ concatMap(id => this.authHttp.delete(VideoService.BASE_VIDEO_URL + '/' + id)),
toArray(),
catchError(err => this.restExtractor.handleError(err))
)
}
private setVideoRate (id: number, rateType: UserVideoRateType) {
- const url = VideoService.BASE_VIDEO_URL + id + '/rate'
+ const url = VideoService.BASE_VIDEO_URL + '/' + id + '/rate'
const body: UserVideoRateUpdate = {
rating: rateType
}
*
*/
-export class AbstractVideosQueryBuilder {
+export class AbstractRunQuery {
protected sequelize: Sequelize
protected query: string
import { createSafeIn } from '@server/models/utils'
import { MUserAccountId } from '@server/types/models'
import validator from 'validator'
-import { AbstractVideosQueryBuilder } from './abstract-videos-query-builder'
-import { VideoTables } from './video-tables'
+import { AbstractRunQuery } from './abstract-run-query'
+import { VideoTableAttributes } from './video-table-attributes'
/**
*
*
*/
-export class AbstractVideosModelQueryBuilder extends AbstractVideosQueryBuilder {
+export class AbstractVideoQueryBuilder extends AbstractRunQuery {
protected attributes: { [key: string]: string } = {}
protected joins = ''
protected where: string
- protected tables: VideoTables
+ protected tables: VideoTableAttributes
constructor (protected readonly mode: 'list' | 'get') {
super()
- this.tables = new VideoTables(this.mode)
+ this.tables = new VideoTableAttributes(this.mode)
}
protected buildSelect () {
import { Sequelize } from 'sequelize'
import { BuildVideoGetQueryOptions } from '../video-model-get-query-builder'
-import { AbstractVideosModelQueryBuilder } from './abstract-videos-model-query-builder'
+import { AbstractVideoQueryBuilder } from './abstract-video-query-builder'
/**
*
*
*/
-export class VideoFileQueryBuilder extends AbstractVideosModelQueryBuilder {
+export class VideoFileQueryBuilder extends AbstractVideoQueryBuilder {
protected attributes: { [key: string]: string }
constructor (protected readonly sequelize: Sequelize) {
import { VideoFileModel } from '../../video-file'
import { VideoLiveModel } from '../../video-live'
import { VideoStreamingPlaylistModel } from '../../video-streaming-playlist'
-import { VideoTables } from './video-tables'
+import { VideoTableAttributes } from './video-table-attributes'
type SQLRow = { [id: string]: string | number }
constructor (
readonly mode: 'get' | 'list',
- readonly tables: VideoTables
+ readonly tables: VideoTableAttributes
) {
}
* Class to build video attributes/join names we want to fetch from the database
*
*/
-export class VideoTables {
+export class VideoTableAttributes {
constructor (readonly mode: 'get' | 'list') {
}
getStreamingPlaylistAttributes () {
- let playlistKeys = [ 'id', 'playlistUrl', 'playlistFilename', 'type' ]
-
- if (this.mode === 'get') {
- playlistKeys = playlistKeys.concat([
- 'p2pMediaLoaderInfohashes',
- 'p2pMediaLoaderPeerVersion',
- 'segmentsSha256Filename',
- 'segmentsSha256Url',
- 'videoId',
- 'createdAt',
- 'updatedAt',
- 'storage'
- ])
- }
-
- return playlistKeys
+ return [
+ 'id',
+ 'playlistUrl',
+ 'playlistFilename',
+ 'type',
+ 'p2pMediaLoaderInfohashes',
+ 'p2pMediaLoaderPeerVersion',
+ 'segmentsSha256Filename',
+ 'segmentsSha256Url',
+ 'videoId',
+ 'createdAt',
+ 'updatedAt',
+ 'storage'
+ ]
}
getUserHistoryAttributes () {
import { Sequelize, Transaction } from 'sequelize'
-import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder'
+import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder'
import { VideoFileQueryBuilder } from './shared/video-file-query-builder'
import { VideoModelBuilder } from './shared/video-model-builder'
-import { VideoTables } from './shared/video-tables'
+import { VideoTableAttributes } from './shared/video-table-attributes'
/**
*
this.webtorrentFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
this.streamingPlaylistFilesQueryBuilder = new VideoFileQueryBuilder(sequelize)
- this.videoModelBuilder = new VideoModelBuilder('get', new VideoTables('get'))
+ this.videoModelBuilder = new VideoModelBuilder('get', new VideoTableAttributes('get'))
}
async queryVideo (options: BuildVideoGetQueryOptions) {
})
if (videos.length > 1) {
- throw new Error('Video results is more than ')
+ throw new Error('Video results is more than 1')
}
if (videos.length === 0) return null
+
return videos[0]
}
}
-export class VideosModelGetQuerySubBuilder extends AbstractVideosModelQueryBuilder {
+export class VideosModelGetQuerySubBuilder extends AbstractVideoQueryBuilder {
protected attributes: { [key: string]: string }
protected webtorrentFilesQuery: string
import { buildDirectionAndField, createSafeIn } from '@server/models/utils'
import { MUserAccountId, MUserId } from '@server/types/models'
import { VideoInclude, VideoPrivacy, VideoState } from '@shared/models'
-import { AbstractVideosQueryBuilder } from './shared/abstract-videos-query-builder'
+import { AbstractRunQuery } from './shared/abstract-run-query'
/**
*
having?: string
}
-export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
+export class VideosIdListQueryBuilder extends AbstractRunQuery {
protected replacements: any = {}
private attributes: string[]
return this.runQuery().then(rows => rows.length !== 0 ? rows[0].total : 0)
}
- getIdsListQueryAndSort (options: BuildVideosListQueryOptions) {
+ getQuery (options: BuildVideosListQueryOptions) {
this.buildIdsListQuery(options)
return { query: this.query, sort: this.sort, replacements: this.replacements }
import { VideoInclude } from '@shared/models'
import { Sequelize } from 'sequelize'
-import { AbstractVideosModelQueryBuilder } from './shared/abstract-videos-model-query-builder'
+import { AbstractVideoQueryBuilder } from './shared/abstract-video-query-builder'
import { VideoModelBuilder } from './shared/video-model-builder'
import { BuildVideosListQueryOptions, VideosIdListQueryBuilder } from './videos-id-list-query-builder'
*
*/
-export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder {
+export class VideosModelListQueryBuilder extends AbstractVideoQueryBuilder {
protected attributes: { [key: string]: string }
private innerQuery: string
queryVideos (options: BuildVideosListQueryOptions) {
this.buildInnerQuery(options)
- this.buildListQueryFromIdsQuery(options)
+ this.buildMainQuery(options)
return this.runQuery()
.then(rows => this.videoModelBuilder.buildVideosFromRows({ rows, include: options.include }))
private buildInnerQuery (options: BuildVideosListQueryOptions) {
const idsQueryBuilder = new VideosIdListQueryBuilder(this.sequelize)
- const { query, sort, replacements } = idsQueryBuilder.getIdsListQueryAndSort(options)
+ const { query, sort, replacements } = idsQueryBuilder.getQuery(options)
this.replacements = replacements
this.innerQuery = query
this.innerSort = sort
}
- private buildListQueryFromIdsQuery (options: BuildVideosListQueryOptions) {
+ private buildMainQuery (options: BuildVideosListQueryOptions) {
this.attributes = {
'"video".*': ''
}
required: false
schema:
type: boolean
- description: 'Display only local or remote videos'
+ description: '**PeerTube >= 4.0** Display only local or remote videos'
include:
name: include
in: query
- 4
- 8
description: >
- Include additional videos in results (can be combined using bitwise or operator)
+ **PeerTube >= 4.0** Include additional videos in results (can be combined using bitwise or operator)
- `0` NONE