]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/commitdiff
Add video file size info in admin videos list
authorChocobozzz <me@florianbigard.com>
Fri, 29 Oct 2021 08:54:27 +0000 (10:54 +0200)
committerChocobozzz <chocobozzz@cpy.re>
Fri, 29 Oct 2021 09:48:21 +0000 (11:48 +0200)
26 files changed:
client/src/app/+admin/overview/videos/video-list.component.html
client/src/app/+admin/overview/videos/video-list.component.scss
client/src/app/+admin/overview/videos/video-list.component.ts
client/src/app/shared/shared-main/video/video-details.model.ts
client/src/app/shared/shared-main/video/video.model.ts
client/src/app/shared/shared-main/video/video.service.ts
server/controllers/api/accounts.ts
server/controllers/api/overviews.ts
server/controllers/api/users/my-subscriptions.ts
server/controllers/api/video-channel.ts
server/controllers/api/videos/index.ts
server/controllers/bots.ts
server/controllers/feeds.ts
server/models/account/account.ts
server/models/user/user-video-history.ts
server/models/video/formatter/video-format-utils.ts
server/models/video/sql/video-model-get-query-builder.ts
server/models/video/sql/videos-id-list-query-builder.ts
server/models/video/sql/videos-model-list-query-builder.ts
server/models/video/video.ts
server/tests/api/videos/videos-common-filters.ts
server/types/models/account/account.ts
server/types/models/server/server.ts
server/types/models/video/video.ts
shared/models/videos/video-include.enum.ts
shared/models/videos/video.model.ts

index 6250c00fb862b4d2010e73570cb1496adc794ebc..eedf6f3dc082ecf02dc29c59029782f910fea7f7 100644 (file)
@@ -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>
 
         <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>
 
   <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>
index 250a917e4ee11b144ad45563af1ba282d5d5b614..158c161af55ede28a1f100292a83812305307728 100644 (file)
@@ -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;
+}
index dd9225e6a8ee80677d0915d1e3f10ea93bb33b3a..6885abfc7835d7490f377ba44482a50928028a63 100644 (file)
@@ -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 = []
 
index f060d1dc943d76ec6ec2a632c7bece2ec3260876..45c053507a0685519d6163db2ae3e2e5666fb9d6 100644 (file)
@@ -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()
   }
index 699eac7f1f3576d49f1b65084e4bedb686feeb56..b11316471fe0772d3e05edcbfebfdea712c294ca 100644 (file)
@@ -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
index 0a3a51b0c62a3bdefaf0ef6747fb69666eee8d43..5db9a8704874bba2731984f5b6274b60e8b6b600 100644 (file)
@@ -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 })
index 44edffe38381d268bd13a2978fd58785da517ab0..46d89bafa1ded3113b94ef54028cb9bfef31a883 100644 (file)
@@ -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
index 68626a5081d60e9119731725f6bec17ab90ceb0f..34585e557f775e9ac97ee03065a3fe9a3eb5a816 100644 (file)
@@ -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
index d9637818030e962d102302e5bc87ba0d4194d083..6799ca8c510bccc9d3ea7cf6405a78af065509f1 100644 (file)
@@ -181,7 +181,6 @@ async function getUserSubscriptionVideos (req: express.Request, res: express.Res
       orLocalVideos: false
     },
     nsfw: buildNSFWFilter(res, query.nsfw),
-    withFiles: false,
     user,
     countVideos
   })
index f9c1a405d907038ca81ef7e5e9d8102a85b7af3d..d1a1e6473d5b6a788913f2cd24faec0dea3d13af 100644 (file)
@@ -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
index 821ed7ff31c327e5cc1b5325a5acaf0aaf03692c..821161c646f0c9c47159320a66c556b8b07fe0ee 100644 (file)
@@ -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')
index 9f03de7e8d152ab5f400e1304ee3cd29a0dd1a1d..2a8d6863a08672bc116a82773e262020ea7820a2 100644 (file)
@@ -76,7 +76,6 @@ async function getSitemapLocalVideoUrls () {
     },
     isLocal: true,
     nsfw: buildNSFWFilter(),
-    withFiles: false,
     countVideos: false
   })
 
index 1f6aebac3b8a53d57572030fefa1f7cae2bb5510..29502a15458d8fd91aba60b893a5dd5e32f0bab4 100644 (file)
@@ -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: {
index 056ec6857597edeb16030fb61918655f44cffa02..71a9b8ccbcf1df75f52bbe185de04b6fc8916f8b 100644 (file)
@@ -99,7 +99,7 @@ export type SummaryOptions = {
       queryInclude.push({
         attributes: [ 'id' ],
         model: AccountBlocklistModel.unscoped(),
-        as: 'BlockedAccounts',
+        as: 'BlockedBy',
         required: false,
         where: {
           accountId: {
index d633cc9d5f1f87d23338749c0e3534828ad92fca..1aefdf02bfa9742f7b0afeb0286b2dae2ff72be0 100644 (file)
@@ -70,7 +70,6 @@ export class UserVideoHistoryModel extends Model<Partial<AttributesOnly<UserVide
         actorId: serverActor.id,
         orLocalVideos: true
       },
-      withFiles: false,
       user,
       historyOfUser: user
     })
index 5dc2c2f1b947c754dc6c4b5c0526d67e0a16b1df..ba49e41aedab8de0068110f1d8aed04fc643f27a 100644 (file)
@@ -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[] {
index d18ddae6781a8c66eeeac0d312b82ffb0383f9f5..2f34d560240baccc5c45ddf213b2a50028e17d15 100644 (file)
@@ -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)
     ])
index 3eb547e75c85303688128833592652910d0edc80..4d6e0ea4bccdf475a97fb20e464aced959507193 100644 (file)
@@ -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()
     }
 
index ef92bd2b04f187e4cb6ef614e592927654a0954f..cd721f05519692676511984934c2d26c28b5777a 100644 (file)
@@ -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()
     }
index 26be34329e4969d02c91c379008a4d2903a518b5..f9618c102fbdcd9450ba1bbd117c7586c0aee9fd 100644 (file)
@@ -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
   }
index eb2d2ab509192fc5eba78b27f14e8af56614e967..03c5c3b3ff198dba071b825c624bdd24d04d867e 100644 (file)
@@ -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 } })
index abe0de27b13861569e4f5ce3b4658be687ab11e5..71f6c79aad45e9a9e92ea14451eff8642b5c6d77 100644 (file)
@@ -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 &
index f8b053e3b9cc2c2479f371b305f3b60677448b92..876186fc0bde041a2dba060a69da1926b8af3331 100644 (file)
@@ -15,7 +15,7 @@ export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'>
 
 export type MServerHostBlocks =
   MServerHost &
-  Use<'BlockedByAccounts', MAccountBlocklistId[]>
+  Use<'BlockedBy', MAccountBlocklistId[]>
 
 // ############################################################################
 
index 16ddaf740e835193b6e20bf02ab2c4863596ad93..9a6b27888aa4a3ca336ac180251e168366b731c2 100644 (file)
@@ -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 &
index fa720b34897bdbb68c277283a71b41bebd393604..72fa8cd301de9087e60b3a40c56dec813adb1712 100644 (file)
@@ -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
 }
index dadde38af1aff5989f65b114c49f6ec9f1d2d338..26cb595e73ab0acf305ca41f7c04e72d3d3fcac3 100644 (file)
@@ -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[]
 }