diff --git a/client/src/app/+admin/overview/videos/video-list.component.html b/client/src/app/+admin/overview/videos/video-list.component.html
index 06da2f96f..6ee4cfadc 100644
--- a/client/src/app/+admin/overview/videos/video-list.component.html
+++ b/client/src/app/+admin/overview/videos/video-list.component.html
@@ -42,7 +42,7 @@
Video |
Info |
- Files |
+ Files |
Published |
diff --git a/packages/tests/src/api/videos/multiple-servers.ts b/packages/tests/src/api/videos/multiple-servers.ts
index 69d13d48e..6a38017f5 100644
--- a/packages/tests/src/api/videos/multiple-servers.ts
+++ b/packages/tests/src/api/videos/multiple-servers.ts
@@ -1,25 +1,25 @@
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
-import { expect } from 'chai'
-import request from 'supertest'
import { wait } from '@peertube/peertube-core-utils'
import { HttpStatusCode, VideoCommentThreadTree, VideoPrivacy } from '@peertube/peertube-models'
import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
import {
+ PeerTubeServer,
cleanupTests,
createMultipleServers,
doubleFollow,
makeGetRequest,
- PeerTubeServer,
setAccessTokensToServers,
setDefaultAccountAvatar,
setDefaultChannelAvatar,
waitJobs
} from '@peertube/peertube-server-commands'
-import { testImageGeneratedByFFmpeg, dateIsValid } from '@tests/shared/checks.js'
+import { dateIsValid, testImageGeneratedByFFmpeg } from '@tests/shared/checks.js'
import { checkTmpIsEmpty } from '@tests/shared/directories.js'
-import { completeVideoCheck, saveVideoInServers, checkVideoFilesWereRemoved } from '@tests/shared/videos.js'
+import { checkVideoFilesWereRemoved, completeVideoCheck, saveVideoInServers } from '@tests/shared/videos.js'
import { checkWebTorrentWorks } from '@tests/shared/webtorrent.js'
+import { expect } from 'chai'
+import request from 'supertest'
describe('Test multiple servers', function () {
let servers: PeerTubeServer[] = []
@@ -367,7 +367,8 @@ describe('Test multiple servers', function () {
})
})
- describe('It should list local videos', function () {
+ describe('Local videos listing', function () {
+
it('Should list only local videos on server 1', async function () {
const { data, total } = await servers[0].videos.list({ isLocal: true })
@@ -397,6 +398,21 @@ describe('Test multiple servers', function () {
})
})
+ describe('All videos listing', function () {
+
+ it('Should list and sort by "localVideoFilesSize"', async function () {
+ const { data, total } = await servers[2].videos.list({ sort: '-localVideoFilesSize' })
+
+ expect(total).to.equal(4)
+ expect(data).to.be.an('array')
+ expect(data.length).to.equal(4)
+ expect(data[0].name).to.equal('my super name for server 3')
+ expect(data[1].name).to.equal('my super name for server 3-2')
+ expect(data[2].isLocal).to.be.false
+ expect(data[3].isLocal).to.be.false
+ })
+ })
+
describe('Should seed the uploaded video', function () {
it('Should add the file 1 by asking server 3', async function () {
diff --git a/server/core/initializers/constants.ts b/server/core/initializers/constants.ts
index d25ce70b4..03259f9d6 100644
--- a/server/core/initializers/constants.ts
+++ b/server/core/initializers/constants.ts
@@ -110,7 +110,19 @@ const SORTABLE_COLUMNS = {
RUNNER_REGISTRATION_TOKENS: [ 'createdAt' ],
RUNNER_JOBS: [ 'updatedAt', 'createdAt', 'priority', 'state', 'progress' ],
- VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'trending', 'hot', 'best' ],
+ VIDEOS: [
+ 'name',
+ 'duration',
+ 'createdAt',
+ 'publishedAt',
+ 'originallyPublishedAt',
+ 'views',
+ 'likes',
+ 'trending',
+ 'hot',
+ 'best',
+ 'localVideoFilesSize'
+ ],
// Don't forget to update peertube-search-index with the same values
VIDEOS_SEARCH: [ 'name', 'duration', 'createdAt', 'publishedAt', 'originallyPublishedAt', 'views', 'likes', 'match' ],
diff --git a/server/core/models/video/sql/video/videos-id-list-query-builder.ts b/server/core/models/video/sql/video/videos-id-list-query-builder.ts
index c19cea166..b5f1e8aac 100644
--- a/server/core/models/video/sql/video/videos-id-list-query-builder.ts
+++ b/server/core/models/video/sql/video/videos-id-list-query-builder.ts
@@ -693,6 +693,23 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
this.attributes.push('COALESCE("video"."originallyPublishedAt", "video"."publishedAt") AS "publishedAtForOrder"')
}
+ if (sort === '-localVideoFilesSize' || sort === 'localVideoFilesSize') {
+ this.attributes.push(
+ '(' +
+ 'CASE ' +
+ 'WHEN "video"."remote" IS TRUE THEN 0 ' + // Consider remote videos with size of 0
+ 'ELSE (' +
+ '(SELECT COALESCE(SUM(size), 0) FROM "videoFile" WHERE "videoFile"."videoId" = "video"."id")' +
+ ' + ' +
+ '(SELECT COALESCE(SUM(size), 0) FROM "videoFile" ' +
+ 'INNER JOIN "videoStreamingPlaylist" ON "videoStreamingPlaylist"."id" = "videoFile"."videoStreamingPlaylistId" ' +
+ 'AND "videoStreamingPlaylist"."videoId" = "video"."id"' +
+ ')' +
+ ') END' +
+ ') AS "localVideoFilesSize"'
+ )
+ }
+
this.sort = this.buildOrder(sort)
}
@@ -712,6 +729,8 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
firstSort = '"similarity"'
} else if (field === 'originallyPublishedAt') {
firstSort = '"publishedAtForOrder"'
+ } else if (field === 'localVideoFilesSize') {
+ firstSort = '"localVideoFilesSize"'
} else if (field.includes('.')) {
firstSort = field
} else {