Add video file size info in admin videos list
This commit is contained in:
parent
2760b454a7
commit
3c10840fa9
26 changed files with 161 additions and 65 deletions
|
@ -37,6 +37,7 @@
|
|||
<th style="width: 60px;"></th>
|
||||
<th i18n>Video</th>
|
||||
<th i18n>Info</th>
|
||||
<th i18n>Files</th>
|
||||
<th style="width: 150px;" i18n pSortableColumn="publishedAt">Published <p-sortIcon field="publishedAt"></p-sortIcon></th>
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
@ -63,8 +64,8 @@
|
|||
<my-video-cell [video]="video"></my-video-cell>
|
||||
</td>
|
||||
|
||||
<td class="badges">
|
||||
<span [ngClass]="getPrivacyBadgeClass(video.privacy.id)" class="badge" i18n>{{ video.privacy.label }}</span>
|
||||
<td>
|
||||
<span [ngClass]="getPrivacyBadgeClass(video.privacy.id)" class="badge">{{ video.privacy.label }}</span>
|
||||
|
||||
<span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span>
|
||||
|
||||
|
@ -76,6 +77,13 @@
|
|||
<span *ngIf="isVideoBlocked(video)" class="badge badge-red" i18n>Blocked</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span *ngIf="isHLS(video)" class="badge badge-blue">HLS</span>
|
||||
<span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent</span>
|
||||
|
||||
<span *ngIf="!video.remote">{{ getFilesSize(video) | bytes: 1 }}</span>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
{{ video.publishedAt | date: 'short' }}
|
||||
</td>
|
||||
|
@ -85,8 +93,30 @@
|
|||
|
||||
<ng-template pTemplate="rowexpansion" let-video>
|
||||
<tr>
|
||||
<td colspan="50">
|
||||
<my-embed [video]="video"></my-embed>
|
||||
<td class="video-info expand-cell" colspan="7">
|
||||
<div>
|
||||
<div *ngIf="isWebTorrent(video)">
|
||||
WebTorrent:
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let file of video.files">
|
||||
{{ file.resolution.label }}: {{ file.size | bytes: 1 }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div *ngIf="isHLS(video)">
|
||||
HLS:
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let file of video.streamingPlaylists[0].files">
|
||||
{{ file.resolution.label }}: {{ file.size | bytes: 1 }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<my-embed class="ml-auto" [video]="video"></my-embed>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</ng-template>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
my-embed {
|
||||
display: block;
|
||||
max-width: 500px;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.badge {
|
||||
|
@ -10,3 +11,7 @@ my-embed {
|
|||
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.video-info > div {
|
||||
display: flex;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import { Component, OnInit } from '@angular/core'
|
|||
import { ActivatedRoute, Router } from '@angular/router'
|
||||
import { AuthService, ConfirmService, Notifier, RestPagination, RestTable } from '@app/core'
|
||||
import { DropdownAction, Video, VideoService } from '@app/shared/shared-main'
|
||||
import { UserRight, VideoPrivacy, VideoState } from '@shared/models'
|
||||
import { UserRight, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models'
|
||||
import { AdvancedInputFilter } from '@app/shared/shared-forms'
|
||||
import { VideoActionsDisplayType } from '@app/shared/shared-video-miniature'
|
||||
|
||||
|
@ -114,6 +114,24 @@ export class VideoListComponent extends RestTable implements OnInit {
|
|||
return video.blacklisted
|
||||
}
|
||||
|
||||
isHLS (video: Video) {
|
||||
return video.streamingPlaylists.some(p => p.type === VideoStreamingPlaylistType.HLS)
|
||||
}
|
||||
|
||||
isWebTorrent (video: Video) {
|
||||
return video.files.length !== 0
|
||||
}
|
||||
|
||||
getFilesSize (video: Video) {
|
||||
let files = video.files
|
||||
|
||||
if (this.isHLS(video)) {
|
||||
files = files.concat(video.streamingPlaylists[0].files)
|
||||
}
|
||||
|
||||
return files.reduce((p, f) => p += f.size, 0)
|
||||
}
|
||||
|
||||
protected reloadData () {
|
||||
this.selectedVideos = []
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
|
|||
support: string
|
||||
channel: VideoChannel
|
||||
tags: string[]
|
||||
files: VideoFile[]
|
||||
account: Account
|
||||
commentsEnabled: boolean
|
||||
downloadEnabled: boolean
|
||||
|
@ -28,13 +27,13 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
|
|||
|
||||
trackerUrls: string[]
|
||||
|
||||
files: VideoFile[]
|
||||
streamingPlaylists: VideoStreamingPlaylist[]
|
||||
|
||||
constructor (hash: VideoDetailsServerModel, translations = {}) {
|
||||
super(hash, translations)
|
||||
|
||||
this.descriptionPath = hash.descriptionPath
|
||||
this.files = hash.files
|
||||
this.channel = new VideoChannel(hash.channel)
|
||||
this.account = new Account(hash.account)
|
||||
this.tags = hash.tags
|
||||
|
@ -43,7 +42,6 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
|
|||
this.downloadEnabled = hash.downloadEnabled
|
||||
|
||||
this.trackerUrls = hash.trackerUrls
|
||||
this.streamingPlaylists = hash.streamingPlaylists
|
||||
|
||||
this.buildLikeAndDislikePercents()
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import {
|
|||
UserRight,
|
||||
Video as VideoServerModel,
|
||||
VideoConstant,
|
||||
VideoFile,
|
||||
VideoPrivacy,
|
||||
VideoScheduleUpdate,
|
||||
VideoState
|
||||
VideoState,
|
||||
VideoStreamingPlaylist
|
||||
} from '@shared/models'
|
||||
|
||||
export class Video implements VideoServerModel {
|
||||
|
@ -96,6 +98,9 @@ export class Video implements VideoServerModel {
|
|||
|
||||
pluginData?: any
|
||||
|
||||
streamingPlaylists?: VideoStreamingPlaylist[]
|
||||
files?: VideoFile[]
|
||||
|
||||
static buildWatchUrl (video: Partial<Pick<Video, 'uuid' | 'shortUUID'>>) {
|
||||
return buildVideoWatchPath({ shortUUID: video.shortUUID || video.uuid })
|
||||
}
|
||||
|
@ -172,6 +177,9 @@ export class Video implements VideoServerModel {
|
|||
this.blockedOwner = hash.blockedOwner
|
||||
this.blockedServer = hash.blockedServer
|
||||
|
||||
this.streamingPlaylists = hash.streamingPlaylists
|
||||
this.files = hash.files
|
||||
|
||||
this.userHistory = hash.userHistory
|
||||
|
||||
this.originInstanceHost = this.account.host
|
||||
|
|
|
@ -208,7 +208,11 @@ export class VideoService {
|
|||
): Observable<ResultList<Video>> {
|
||||
const { pagination, search } = parameters
|
||||
|
||||
const include = VideoInclude.BLACKLISTED | VideoInclude.BLOCKED_OWNER | VideoInclude.HIDDEN_PRIVACY | VideoInclude.NOT_PUBLISHED_STATE
|
||||
const include = VideoInclude.BLACKLISTED |
|
||||
VideoInclude.BLOCKED_OWNER |
|
||||
VideoInclude.HIDDEN_PRIVACY |
|
||||
VideoInclude.NOT_PUBLISHED_STATE |
|
||||
VideoInclude.FILES
|
||||
|
||||
let params = new HttpParams()
|
||||
params = this.buildCommonVideosParams({ params, include, ...parameters })
|
||||
|
|
|
@ -189,7 +189,6 @@ async function listAccountVideos (req: express.Request, res: express.Response) {
|
|||
|
||||
displayOnlyForFollower,
|
||||
nsfw: buildNSFWFilter(res, query.nsfw),
|
||||
withFiles: false,
|
||||
accountId: account.id,
|
||||
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
||||
countVideos
|
||||
|
|
|
@ -122,7 +122,6 @@ async function getVideos (
|
|||
},
|
||||
nsfw: buildNSFWFilter(res),
|
||||
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
||||
withFiles: false,
|
||||
countVideos: false,
|
||||
|
||||
...where
|
||||
|
|
|
@ -181,7 +181,6 @@ async function getUserSubscriptionVideos (req: express.Request, res: express.Res
|
|||
orLocalVideos: false
|
||||
},
|
||||
nsfw: buildNSFWFilter(res, query.nsfw),
|
||||
withFiles: false,
|
||||
user,
|
||||
countVideos
|
||||
})
|
||||
|
|
|
@ -347,7 +347,6 @@ async function listVideoChannelVideos (req: express.Request, res: express.Respon
|
|||
|
||||
displayOnlyForFollower,
|
||||
nsfw: buildNSFWFilter(res, query.nsfw),
|
||||
withFiles: false,
|
||||
videoChannelId: videoChannelInstance.id,
|
||||
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
||||
countVideos
|
||||
|
|
|
@ -225,7 +225,6 @@ async function listVideos (req: express.Request, res: express.Response) {
|
|||
orLocalVideos: true
|
||||
},
|
||||
nsfw: buildNSFWFilter(res, query.nsfw),
|
||||
withFiles: false,
|
||||
user: res.locals.oauth ? res.locals.oauth.token.User : undefined,
|
||||
countVideos
|
||||
}, 'filter:api.videos.list.params')
|
||||
|
|
|
@ -76,7 +76,6 @@ async function getSitemapLocalVideoUrls () {
|
|||
},
|
||||
isLocal: true,
|
||||
nsfw: buildNSFWFilter(),
|
||||
withFiles: false,
|
||||
countVideos: false
|
||||
})
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import express from 'express'
|
|||
import Feed from 'pfeed'
|
||||
import { getServerActor } from '@server/models/application/application'
|
||||
import { getCategoryLabel } from '@server/models/video/formatter/video-format-utils'
|
||||
import { VideoInclude } from '@shared/models'
|
||||
import { buildNSFWFilter } from '../helpers/express-utils'
|
||||
import { CONFIG } from '../initializers/config'
|
||||
import { FEEDS, PREVIEWS_SIZE, ROUTE_CACHE_LIFETIME, WEBSERVER } from '../initializers/constants'
|
||||
|
@ -171,8 +172,8 @@ async function generateVideoFeed (req: express.Request, res: express.Response) {
|
|||
},
|
||||
nsfw,
|
||||
isLocal: req.query.isLocal,
|
||||
include: req.query.include,
|
||||
withFiles: true,
|
||||
include: req.query.include | VideoInclude.FILES,
|
||||
hasFiles: true,
|
||||
countVideos: false,
|
||||
...options
|
||||
})
|
||||
|
@ -204,9 +205,10 @@ async function generateVideoFeedForSubscriptions (req: express.Request, res: exp
|
|||
nsfw,
|
||||
|
||||
isLocal: req.query.isLocal,
|
||||
include: req.query.include,
|
||||
|
||||
withFiles: true,
|
||||
hasFiles: true,
|
||||
include: req.query.include | VideoInclude.FILES,
|
||||
|
||||
countVideos: false,
|
||||
|
||||
displayOnlyForFollower: {
|
||||
|
|
|
@ -99,7 +99,7 @@ export type SummaryOptions = {
|
|||
queryInclude.push({
|
||||
attributes: [ 'id' ],
|
||||
model: AccountBlocklistModel.unscoped(),
|
||||
as: 'BlockedAccounts',
|
||||
as: 'BlockedBy',
|
||||
required: false,
|
||||
where: {
|
||||
accountId: {
|
||||
|
|
|
@ -70,7 +70,6 @@ export class UserVideoHistoryModel extends Model<Partial<AttributesOnly<UserVide
|
|||
actorId: serverActor.id,
|
||||
orLocalVideos: true
|
||||
},
|
||||
withFiles: false,
|
||||
user,
|
||||
historyOfUser: user
|
||||
})
|
||||
|
|
|
@ -42,6 +42,7 @@ export type VideoFormattingJSONOptions = {
|
|||
waitTranscoding?: boolean
|
||||
scheduledUpdate?: boolean
|
||||
blacklistInfo?: boolean
|
||||
files?: boolean
|
||||
blockedOwner?: boolean
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +56,7 @@ function guessAdditionalAttributesFromQuery (query: VideosCommonQueryAfterSaniti
|
|||
waitTranscoding: !!(query.include & VideoInclude.NOT_PUBLISHED_STATE),
|
||||
scheduledUpdate: !!(query.include & VideoInclude.NOT_PUBLISHED_STATE),
|
||||
blacklistInfo: !!(query.include & VideoInclude.BLACKLISTED),
|
||||
files: !!(query.include & VideoInclude.FILES),
|
||||
blockedOwner: !!(query.include & VideoInclude.BLOCKED_OWNER)
|
||||
}
|
||||
}
|
||||
|
@ -150,22 +152,26 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options: VideoForm
|
|||
videoObject.blockedServer = !!(server?.isBlocked())
|
||||
}
|
||||
|
||||
if (add?.files === true) {
|
||||
videoObject.streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists)
|
||||
videoObject.files = videoFilesModelToFormattedJSON(video, video.VideoFiles)
|
||||
}
|
||||
|
||||
return videoObject
|
||||
}
|
||||
|
||||
function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): VideoDetails {
|
||||
const formattedJson = video.toFormattedJSON({
|
||||
const videoJSON = video.toFormattedJSON({
|
||||
additionalAttributes: {
|
||||
scheduledUpdate: true,
|
||||
blacklistInfo: true
|
||||
blacklistInfo: true,
|
||||
files: true
|
||||
}
|
||||
})
|
||||
}) as Video & Required<Pick<Video, 'files' | 'streamingPlaylists'>>
|
||||
|
||||
const tags = video.Tags ? video.Tags.map(t => t.name) : []
|
||||
|
||||
const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists)
|
||||
|
||||
const detailsJson = {
|
||||
const detailsJSON = {
|
||||
support: video.support,
|
||||
descriptionPath: video.getDescriptionAPIPath(),
|
||||
channel: video.VideoChannel.toFormattedJSON(),
|
||||
|
@ -179,20 +185,14 @@ function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): Vid
|
|||
label: getStateLabel(video.state)
|
||||
},
|
||||
|
||||
trackerUrls: video.getTrackerUrls(),
|
||||
|
||||
files: [],
|
||||
streamingPlaylists
|
||||
trackerUrls: video.getTrackerUrls()
|
||||
}
|
||||
|
||||
// Format and sort video files
|
||||
detailsJson.files = videoFilesModelToFormattedJSON(video, video.VideoFiles)
|
||||
|
||||
return Object.assign(formattedJson, detailsJson)
|
||||
return Object.assign(videoJSON, detailsJSON)
|
||||
}
|
||||
|
||||
function streamingPlaylistsModelToFormattedJSON (
|
||||
video: MVideoFormattableDetails,
|
||||
video: MVideoFormattable,
|
||||
playlists: MStreamingPlaylistRedundanciesOpt[]
|
||||
): VideoStreamingPlaylist[] {
|
||||
if (isArray(playlists) === false) return []
|
||||
|
@ -223,7 +223,7 @@ function sortByResolutionDesc (fileA: MVideoFile, fileB: MVideoFile) {
|
|||
}
|
||||
|
||||
function videoFilesModelToFormattedJSON (
|
||||
video: MVideoFormattableDetails,
|
||||
video: MVideoFormattable,
|
||||
videoFiles: MVideoFileRedundanciesOpt[],
|
||||
includeMagnet = true
|
||||
): VideoFile[] {
|
||||
|
|
|
@ -32,7 +32,7 @@ export type BuildVideoGetQueryOptions = {
|
|||
logging?: boolean
|
||||
}
|
||||
|
||||
export class VideosModelGetQueryBuilder {
|
||||
export class VideoModelGetQueryBuilder {
|
||||
videoQueryBuilder: VideosModelGetQuerySubBuilder
|
||||
webtorrentFilesQueryBuilder: VideoFileQueryBuilder
|
||||
streamingPlaylistFilesQueryBuilder: VideoFileQueryBuilder
|
||||
|
@ -53,11 +53,11 @@ export class VideosModelGetQueryBuilder {
|
|||
const [ videoRows, webtorrentFilesRows, streamingPlaylistFilesRows ] = await Promise.all([
|
||||
this.videoQueryBuilder.queryVideos(options),
|
||||
|
||||
VideosModelGetQueryBuilder.videoFilesInclude.has(options.type)
|
||||
VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
|
||||
? this.webtorrentFilesQueryBuilder.queryWebTorrentVideos(options)
|
||||
: Promise.resolve(undefined),
|
||||
|
||||
VideosModelGetQueryBuilder.videoFilesInclude.has(options.type)
|
||||
VideoModelGetQueryBuilder.videoFilesInclude.has(options.type)
|
||||
? this.streamingPlaylistFilesQueryBuilder.queryStreamingPlaylistVideos(options)
|
||||
: Promise.resolve(undefined)
|
||||
])
|
||||
|
|
|
@ -43,7 +43,7 @@ export type BuildVideosListQueryOptions = {
|
|||
|
||||
uuids?: string[]
|
||||
|
||||
withFiles?: boolean
|
||||
hasFiles?: boolean
|
||||
|
||||
accountId?: number
|
||||
videoChannelId?: number
|
||||
|
@ -165,7 +165,7 @@ export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
|
|||
this.whereFollowerActorId(options.displayOnlyForFollower)
|
||||
}
|
||||
|
||||
if (options.withFiles === true) {
|
||||
if (options.hasFiles === true) {
|
||||
this.whereFileExists()
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ export class VideosModelListQueryBuilder extends AbstractVideosModelQueryBuilder
|
|||
this.includeAccounts()
|
||||
this.includeThumbnails()
|
||||
|
||||
if (options.withFiles) {
|
||||
if (options.include & VideoInclude.FILES) {
|
||||
this.includeWebtorrentFiles()
|
||||
this.includeStreamingPlaylistFiles()
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ import {
|
|||
videoModelToFormattedJSON
|
||||
} from './formatter/video-format-utils'
|
||||
import { ScheduleVideoUpdateModel } from './schedule-video-update'
|
||||
import { VideosModelGetQueryBuilder } from './sql/video-model-get-query-builder'
|
||||
import { VideoModelGetQueryBuilder } from './sql/video-model-get-query-builder'
|
||||
import { BuildVideosListQueryOptions, DisplayOnlyForFollowerOptions, VideosIdListQueryBuilder } from './sql/videos-id-list-query-builder'
|
||||
import { VideosModelListQueryBuilder } from './sql/videos-model-list-query-builder'
|
||||
import { TagModel } from './tag'
|
||||
|
@ -1029,7 +1029,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
isLocal?: boolean
|
||||
include?: VideoInclude
|
||||
|
||||
withFiles: boolean
|
||||
hasFiles?: boolean // default false
|
||||
|
||||
categoryOneOf?: number[]
|
||||
licenceOneOf?: number[]
|
||||
|
@ -1053,7 +1053,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
|
||||
search?: string
|
||||
}) {
|
||||
if (options.include && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
||||
if (VideoModel.isPrivateInclude(options.include) && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
||||
throw new Error('Try to filter all-local but no user has not the see all videos right')
|
||||
}
|
||||
|
||||
|
@ -1082,7 +1082,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
'isLocal',
|
||||
'include',
|
||||
'displayOnlyForFollower',
|
||||
'withFiles',
|
||||
'hasFiles',
|
||||
'accountId',
|
||||
'videoChannelId',
|
||||
'videoPlaylistId',
|
||||
|
@ -1229,13 +1229,13 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
}
|
||||
|
||||
static load (id: number | string, transaction?: Transaction): Promise<MVideoThumbnail> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails' })
|
||||
}
|
||||
|
||||
static loadWithBlacklist (id: number | string, transaction?: Transaction): Promise<MVideoThumbnailBlacklist> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction, type: 'thumbnails-blacklist' })
|
||||
}
|
||||
|
@ -1279,31 +1279,31 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
}
|
||||
|
||||
static loadOnlyId (id: number | string, transaction?: Transaction): Promise<MVideoId> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction, type: 'id' })
|
||||
}
|
||||
|
||||
static loadWithFiles (id: number | string, transaction?: Transaction, logging?: boolean): Promise<MVideoWithAllFiles> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction, type: 'all-files', logging })
|
||||
}
|
||||
|
||||
static loadByUrl (url: string, transaction?: Transaction): Promise<MVideoThumbnail> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ url, transaction, type: 'thumbnails' })
|
||||
}
|
||||
|
||||
static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Promise<MVideoAccountLightBlacklistAllFiles> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ url, transaction, type: 'account-blacklist-files' })
|
||||
}
|
||||
|
||||
static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Promise<MVideoFullLight> {
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction: t, type: 'full-light', userId })
|
||||
}
|
||||
|
@ -1314,7 +1314,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
userId?: number
|
||||
}): Promise<MVideoDetails> {
|
||||
const { id, transaction, userId } = parameters
|
||||
const queryBuilder = new VideosModelGetQueryBuilder(VideoModel.sequelize)
|
||||
const queryBuilder = new VideoModelGetQueryBuilder(VideoModel.sequelize)
|
||||
|
||||
return queryBuilder.queryVideo({ id, transaction, type: 'api', userId })
|
||||
}
|
||||
|
@ -1345,8 +1345,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
displayOnlyForFollower: {
|
||||
actorId: serverActor.id,
|
||||
orLocalVideos: true
|
||||
},
|
||||
withFiles: false
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
|
@ -1490,6 +1489,13 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
|||
}
|
||||
}
|
||||
|
||||
private static isPrivateInclude (include: VideoInclude) {
|
||||
return include & VideoInclude.BLACKLISTED ||
|
||||
include & VideoInclude.BLOCKED_OWNER ||
|
||||
include & VideoInclude.HIDDEN_PRIVACY ||
|
||||
include & VideoInclude.NOT_PUBLISHED_STATE
|
||||
}
|
||||
|
||||
isBlacklisted () {
|
||||
return !!this.VideoBlacklist
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
setDefaultVideoChannel,
|
||||
waitJobs
|
||||
} from '@shared/extra-utils'
|
||||
import { HttpStatusCode, UserRole, Video, VideoInclude, VideoPrivacy } from '@shared/models'
|
||||
import { HttpStatusCode, UserRole, Video, VideoDetails, VideoInclude, VideoPrivacy } from '@shared/models'
|
||||
|
||||
describe('Test videos filter', function () {
|
||||
let servers: PeerTubeServer[]
|
||||
|
@ -365,6 +365,32 @@ describe('Test videos filter', function () {
|
|||
await servers[0].blocklist.removeFromServerBlocklist({ server: servers[1].host })
|
||||
})
|
||||
|
||||
it('Should include video files', async function () {
|
||||
for (const path of paths) {
|
||||
{
|
||||
const videos = await listVideos({ server: servers[0], path })
|
||||
|
||||
for (const video of videos) {
|
||||
const videoWithFiles = video as VideoDetails
|
||||
|
||||
expect(videoWithFiles.files).to.not.exist
|
||||
expect(videoWithFiles.streamingPlaylists).to.not.exist
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const videos = await listVideos({ server: servers[0], path, include: VideoInclude.FILES })
|
||||
|
||||
for (const video of videos) {
|
||||
const videoWithFiles = video as VideoDetails
|
||||
|
||||
expect(videoWithFiles.files).to.exist
|
||||
expect(videoWithFiles.files).to.have.length.at.least(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
it('Should filter by tags and category', async function () {
|
||||
await servers[0].videos.upload({ attributes: { name: 'tag filter', tags: [ 'tag1', 'tag2' ] } })
|
||||
await servers[0].videos.upload({ attributes: { name: 'tag filter with category', tags: [ 'tag3' ], category: 4 } })
|
||||
|
|
|
@ -23,7 +23,7 @@ type Use<K extends keyof AccountModel, M> = PickWith<AccountModel, K, M>
|
|||
|
||||
export type MAccount =
|
||||
Omit<AccountModel, 'Actor' | 'User' | 'Application' | 'VideoChannels' | 'VideoPlaylists' |
|
||||
'VideoComments' | 'BlockedAccounts'>
|
||||
'VideoComments' | 'BlockedBy'>
|
||||
|
||||
// ############################################################################
|
||||
|
||||
|
@ -84,7 +84,7 @@ export type MAccountSummary =
|
|||
|
||||
export type MAccountSummaryBlocks =
|
||||
MAccountSummary &
|
||||
Use<'BlockedByAccounts', MAccountBlocklistId[]>
|
||||
Use<'BlockedBy', MAccountBlocklistId[]>
|
||||
|
||||
export type MAccountAPI =
|
||||
MAccount &
|
||||
|
|
|
@ -15,7 +15,7 @@ export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'>
|
|||
|
||||
export type MServerHostBlocks =
|
||||
MServerHost &
|
||||
Use<'BlockedByAccounts', MAccountBlocklistId[]>
|
||||
Use<'BlockedBy', MAccountBlocklistId[]>
|
||||
|
||||
// ############################################################################
|
||||
|
||||
|
|
|
@ -210,7 +210,9 @@ export type MVideoFormattable =
|
|||
PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> &
|
||||
Use<'VideoChannel', MChannelAccountSummaryFormattable> &
|
||||
PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> &
|
||||
PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>>
|
||||
PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>> &
|
||||
PickWithOpt<VideoModel, 'VideoStreamingPlaylists', MStreamingPlaylistFiles[]> &
|
||||
PickWithOpt<VideoModel, 'VideoFiles', MVideoFile[]>
|
||||
|
||||
export type MVideoFormattableDetails =
|
||||
MVideoFormattable &
|
||||
|
|
|
@ -3,5 +3,6 @@ export const enum VideoInclude {
|
|||
NOT_PUBLISHED_STATE = 1 << 0,
|
||||
HIDDEN_PRIVACY = 1 << 1,
|
||||
BLACKLISTED = 1 << 2,
|
||||
BLOCKED_OWNER = 1 << 3
|
||||
BLOCKED_OWNER = 1 << 3,
|
||||
FILES = 1 << 4
|
||||
}
|
||||
|
|
|
@ -62,6 +62,9 @@ export interface Video {
|
|||
|
||||
blockedOwner?: boolean
|
||||
blockedServer?: boolean
|
||||
|
||||
files?: VideoFile[]
|
||||
streamingPlaylists?: VideoStreamingPlaylist[]
|
||||
}
|
||||
|
||||
export interface VideoDetails extends Video {
|
||||
|
@ -70,7 +73,6 @@ export interface VideoDetails extends Video {
|
|||
channel: VideoChannel
|
||||
account: Account
|
||||
tags: string[]
|
||||
files: VideoFile[]
|
||||
commentsEnabled: boolean
|
||||
downloadEnabled: boolean
|
||||
|
||||
|
@ -80,5 +82,6 @@ export interface VideoDetails extends Video {
|
|||
|
||||
trackerUrls: string[]
|
||||
|
||||
files: VideoFile[]
|
||||
streamingPlaylists: VideoStreamingPlaylist[]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue