Add ability to filter by file type
This commit is contained in:
parent
d5d9c5b79e
commit
d324756edb
10 changed files with 237 additions and 40 deletions
|
@ -45,11 +45,33 @@ export class VideoAdminService {
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
queryParams: { search: 'isLive:false' },
|
queryParams: { search: 'isLive:false' },
|
||||||
label: $localize`VOD videos`
|
label: $localize`VOD`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
queryParams: { search: 'isLive:true' },
|
queryParams: { search: 'isLive:true' },
|
||||||
label: $localize`Live videos`
|
label: $localize`Live`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
title: $localize`Video files`,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
queryParams: { search: 'webtorrent:true' },
|
||||||
|
label: $localize`With WebTorrent`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryParams: { search: 'webtorrent:false' },
|
||||||
|
label: $localize`Without WebTorrent`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryParams: { search: 'hls:true' },
|
||||||
|
label: $localize`With HLS`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
queryParams: { search: 'hls:false' },
|
||||||
|
label: $localize`Without HLS`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -69,7 +91,7 @@ export class VideoAdminService {
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: $localize`Include/Exclude`,
|
title: $localize`Exclude`,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
queryParams: { search: 'excludeMuted' },
|
queryParams: { search: 'excludeMuted' },
|
||||||
|
@ -94,6 +116,14 @@ export class VideoAdminService {
|
||||||
prefix: 'isLocal:',
|
prefix: 'isLocal:',
|
||||||
isBoolean: true
|
isBoolean: true
|
||||||
},
|
},
|
||||||
|
hasHLSFiles: {
|
||||||
|
prefix: 'hls:',
|
||||||
|
isBoolean: true
|
||||||
|
},
|
||||||
|
hasWebtorrentFiles: {
|
||||||
|
prefix: 'webtorrent:',
|
||||||
|
isBoolean: true
|
||||||
|
},
|
||||||
isLive: {
|
isLive: {
|
||||||
prefix: 'isLive:',
|
prefix: 'isLive:',
|
||||||
isBoolean: true
|
isBoolean: true
|
||||||
|
|
|
@ -66,11 +66,11 @@
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<span [ngClass]="getPrivacyBadgeClass(video.privacy.id)" class="badge">{{ video.privacy.label }}</span>
|
<span [ngClass]="getPrivacyBadgeClass(video)" class="badge">{{ video.privacy.label }}</span>
|
||||||
|
|
||||||
<span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span>
|
<span *ngIf="video.nsfw" class="badge badge-red" i18n>NSFW</span>
|
||||||
|
|
||||||
<span *ngIf="isUnpublished(video.state.id)" class="badge badge-yellow" i18n>{{ video.state.label }}</span>
|
<span *ngIf="isUnpublished(video)" class="badge badge-yellow" i18n>{{ video.state.label }}</span>
|
||||||
|
|
||||||
<span *ngIf="isAccountBlocked(video)" class="badge badge-red" i18n>Account muted</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>
|
<span *ngIf="isServerBlocked(video)" class="badge badge-red" i18n>Server muted</span>
|
||||||
|
@ -83,7 +83,7 @@
|
||||||
<span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent</span>
|
<span *ngIf="isWebTorrent(video)" class="badge badge-blue">WebTorrent</span>
|
||||||
<span *ngIf="video.isLive" class="badge badge-blue">Live</span>
|
<span *ngIf="video.isLive" class="badge badge-blue">Live</span>
|
||||||
|
|
||||||
<span *ngIf="!video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span>
|
<span *ngIf="!isImport(video) && !video.isLive && video.isLocal">{{ getFilesSize(video) | bytes: 1 }}</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
|
|
|
@ -85,14 +85,14 @@ export class VideoListComponent extends RestTable implements OnInit {
|
||||||
this.reloadData()
|
this.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrivacyBadgeClass (privacy: VideoPrivacy) {
|
getPrivacyBadgeClass (video: Video) {
|
||||||
if (privacy === VideoPrivacy.PUBLIC) return 'badge-blue'
|
if (video.privacy.id === VideoPrivacy.PUBLIC) return 'badge-blue'
|
||||||
|
|
||||||
return 'badge-yellow'
|
return 'badge-yellow'
|
||||||
}
|
}
|
||||||
|
|
||||||
isUnpublished (state: VideoState) {
|
isUnpublished (video: Video) {
|
||||||
return state !== VideoState.LIVE_ENDED && state !== VideoState.PUBLISHED
|
return video.state.id !== VideoState.LIVE_ENDED && video.state.id !== VideoState.PUBLISHED
|
||||||
}
|
}
|
||||||
|
|
||||||
isAccountBlocked (video: Video) {
|
isAccountBlocked (video: Video) {
|
||||||
|
@ -107,6 +107,10 @@ export class VideoListComponent extends RestTable implements OnInit {
|
||||||
return video.blacklisted
|
return video.blacklisted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isImport (video: Video) {
|
||||||
|
return video.state.id === VideoState.TO_IMPORT
|
||||||
|
}
|
||||||
|
|
||||||
isHLS (video: Video) {
|
isHLS (video: Video) {
|
||||||
const p = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
|
const p = video.streamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
|
||||||
if (!p) return false
|
if (!p) return false
|
||||||
|
|
|
@ -21,6 +21,8 @@ function pickCommonVideoQuery (query: VideosCommonQueryAfterSanitize) {
|
||||||
'isLocal',
|
'isLocal',
|
||||||
'include',
|
'include',
|
||||||
'skipCount',
|
'skipCount',
|
||||||
|
'hasHLSFiles',
|
||||||
|
'hasWebtorrentFiles',
|
||||||
'search'
|
'search'
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
|
@ -496,6 +496,14 @@ const commonVideosFiltersValidator = [
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(toBooleanOrNull)
|
.customSanitizer(toBooleanOrNull)
|
||||||
.custom(isBooleanValid).withMessage('Should have a valid local boolean'),
|
.custom(isBooleanValid).withMessage('Should have a valid local boolean'),
|
||||||
|
query('hasHLSFiles')
|
||||||
|
.optional()
|
||||||
|
.customSanitizer(toBooleanOrNull)
|
||||||
|
.custom(isBooleanValid).withMessage('Should have a valid has hls boolean'),
|
||||||
|
query('hasWebtorrentFiles')
|
||||||
|
.optional()
|
||||||
|
.customSanitizer(toBooleanOrNull)
|
||||||
|
.custom(isBooleanValid).withMessage('Should have a valid has webtorrent boolean'),
|
||||||
query('skipCount')
|
query('skipCount')
|
||||||
.optional()
|
.optional()
|
||||||
.customSanitizer(toBooleanOrNull)
|
.customSanitizer(toBooleanOrNull)
|
||||||
|
@ -525,12 +533,13 @@ const commonVideosFiltersValidator = [
|
||||||
|
|
||||||
const user = res.locals.oauth?.token.User
|
const user = res.locals.oauth?.token.User
|
||||||
|
|
||||||
if (req.query.include && (!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) !== true)) {
|
if ((!user || user.hasRight(UserRight.SEE_ALL_VIDEOS) !== true)) {
|
||||||
res.fail({
|
if (req.query.include) {
|
||||||
status: HttpStatusCode.UNAUTHORIZED_401,
|
return res.fail({
|
||||||
message: 'You are not allowed to see all local videos.'
|
status: HttpStatusCode.UNAUTHORIZED_401,
|
||||||
})
|
message: 'You are not allowed to see all videos.'
|
||||||
return
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return next()
|
return next()
|
||||||
|
|
|
@ -44,6 +44,8 @@ export type BuildVideosListQueryOptions = {
|
||||||
uuids?: string[]
|
uuids?: string[]
|
||||||
|
|
||||||
hasFiles?: boolean
|
hasFiles?: boolean
|
||||||
|
hasHLSFiles?: boolean
|
||||||
|
hasWebtorrentFiles?: boolean
|
||||||
|
|
||||||
accountId?: number
|
accountId?: number
|
||||||
videoChannelId?: number
|
videoChannelId?: number
|
||||||
|
@ -169,6 +171,14 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
|
||||||
this.whereFileExists()
|
this.whereFileExists()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exists(options.hasWebtorrentFiles)) {
|
||||||
|
this.whereWebTorrentFileExists(options.hasWebtorrentFiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exists(options.hasHLSFiles)) {
|
||||||
|
this.whereHLSFileExists(options.hasHLSFiles)
|
||||||
|
}
|
||||||
|
|
||||||
if (options.tagsOneOf) {
|
if (options.tagsOneOf) {
|
||||||
this.whereTagsOneOf(options.tagsOneOf)
|
this.whereTagsOneOf(options.tagsOneOf)
|
||||||
}
|
}
|
||||||
|
@ -371,16 +381,31 @@ export class VideosIdListQueryBuilder extends AbstractRunQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
private whereFileExists () {
|
private whereFileExists () {
|
||||||
this.and.push(
|
this.and.push(`(${this.buildWebTorrentFileExistsQuery(true)} OR ${this.buildHLSFileExistsQuery(true)})`)
|
||||||
'(' +
|
}
|
||||||
' EXISTS (SELECT 1 FROM "videoFile" WHERE "videoFile"."videoId" = "video"."id") ' +
|
|
||||||
' OR EXISTS (' +
|
private whereWebTorrentFileExists (exists: boolean) {
|
||||||
' SELECT 1 FROM "videoStreamingPlaylist" ' +
|
this.and.push(this.buildWebTorrentFileExistsQuery(exists))
|
||||||
' INNER JOIN "videoFile" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist"."id" ' +
|
}
|
||||||
' WHERE "videoStreamingPlaylist"."videoId" = "video"."id"' +
|
|
||||||
' )' +
|
private whereHLSFileExists (exists: boolean) {
|
||||||
')'
|
this.and.push(this.buildHLSFileExistsQuery(exists))
|
||||||
)
|
}
|
||||||
|
|
||||||
|
private buildWebTorrentFileExistsQuery (exists: boolean) {
|
||||||
|
const prefix = exists ? '' : 'NOT '
|
||||||
|
|
||||||
|
return prefix + 'EXISTS (SELECT 1 FROM "videoFile" WHERE "videoFile"."videoId" = "video"."id")'
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildHLSFileExistsQuery (exists: boolean) {
|
||||||
|
const prefix = exists ? '' : 'NOT '
|
||||||
|
|
||||||
|
return prefix + 'EXISTS (' +
|
||||||
|
' SELECT 1 FROM "videoStreamingPlaylist" ' +
|
||||||
|
' INNER JOIN "videoFile" ON "videoFile"."videoStreamingPlaylistId" = "videoStreamingPlaylist"."id" ' +
|
||||||
|
' WHERE "videoStreamingPlaylist"."videoId" = "video"."id"' +
|
||||||
|
')'
|
||||||
}
|
}
|
||||||
|
|
||||||
private whereTagsOneOf (tagsOneOf: string[]) {
|
private whereTagsOneOf (tagsOneOf: string[]) {
|
||||||
|
|
|
@ -1030,6 +1030,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
include?: VideoInclude
|
include?: VideoInclude
|
||||||
|
|
||||||
hasFiles?: boolean // default false
|
hasFiles?: boolean // default false
|
||||||
|
hasWebtorrentFiles?: boolean
|
||||||
|
hasHLSFiles?: boolean
|
||||||
|
|
||||||
categoryOneOf?: number[]
|
categoryOneOf?: number[]
|
||||||
licenceOneOf?: number[]
|
licenceOneOf?: number[]
|
||||||
|
@ -1053,9 +1055,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
|
|
||||||
search?: string
|
search?: string
|
||||||
}) {
|
}) {
|
||||||
if (VideoModel.isPrivateInclude(options.include) && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user)
|
||||||
throw new Error('Try to filter all-local but no user has not the see all videos right')
|
|
||||||
}
|
|
||||||
|
|
||||||
const trendingDays = options.sort.endsWith('trending')
|
const trendingDays = options.sort.endsWith('trending')
|
||||||
? CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS
|
? CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS
|
||||||
|
@ -1088,6 +1088,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
'videoPlaylistId',
|
'videoPlaylistId',
|
||||||
'user',
|
'user',
|
||||||
'historyOfUser',
|
'historyOfUser',
|
||||||
|
'hasHLSFiles',
|
||||||
|
'hasWebtorrentFiles',
|
||||||
'search'
|
'search'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
|
@ -1103,27 +1105,39 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
start: number
|
start: number
|
||||||
count: number
|
count: number
|
||||||
sort: string
|
sort: string
|
||||||
search?: string
|
|
||||||
host?: string
|
|
||||||
startDate?: string // ISO 8601
|
|
||||||
endDate?: string // ISO 8601
|
|
||||||
originallyPublishedStartDate?: string
|
|
||||||
originallyPublishedEndDate?: string
|
|
||||||
nsfw?: boolean
|
nsfw?: boolean
|
||||||
isLive?: boolean
|
isLive?: boolean
|
||||||
isLocal?: boolean
|
isLocal?: boolean
|
||||||
include?: VideoInclude
|
include?: VideoInclude
|
||||||
|
|
||||||
categoryOneOf?: number[]
|
categoryOneOf?: number[]
|
||||||
licenceOneOf?: number[]
|
licenceOneOf?: number[]
|
||||||
languageOneOf?: string[]
|
languageOneOf?: string[]
|
||||||
tagsOneOf?: string[]
|
tagsOneOf?: string[]
|
||||||
tagsAllOf?: string[]
|
tagsAllOf?: string[]
|
||||||
|
|
||||||
|
displayOnlyForFollower: DisplayOnlyForFollowerOptions | null
|
||||||
|
|
||||||
|
user?: MUserAccountId
|
||||||
|
|
||||||
|
hasWebtorrentFiles?: boolean
|
||||||
|
hasHLSFiles?: boolean
|
||||||
|
|
||||||
|
search?: string
|
||||||
|
|
||||||
|
host?: string
|
||||||
|
startDate?: string // ISO 8601
|
||||||
|
endDate?: string // ISO 8601
|
||||||
|
originallyPublishedStartDate?: string
|
||||||
|
originallyPublishedEndDate?: string
|
||||||
|
|
||||||
durationMin?: number // seconds
|
durationMin?: number // seconds
|
||||||
durationMax?: number // seconds
|
durationMax?: number // seconds
|
||||||
user?: MUserAccountId
|
|
||||||
uuids?: string[]
|
uuids?: string[]
|
||||||
displayOnlyForFollower: DisplayOnlyForFollowerOptions | null
|
|
||||||
}) {
|
}) {
|
||||||
|
VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user)
|
||||||
|
|
||||||
const serverActor = await getServerActor()
|
const serverActor = await getServerActor()
|
||||||
|
|
||||||
const queryOptions = {
|
const queryOptions = {
|
||||||
|
@ -1148,6 +1162,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
'originallyPublishedEndDate',
|
'originallyPublishedEndDate',
|
||||||
'durationMin',
|
'durationMin',
|
||||||
'durationMax',
|
'durationMax',
|
||||||
|
'hasHLSFiles',
|
||||||
|
'hasWebtorrentFiles',
|
||||||
'uuids',
|
'uuids',
|
||||||
'search',
|
'search',
|
||||||
'displayOnlyForFollower'
|
'displayOnlyForFollower'
|
||||||
|
@ -1489,6 +1505,12 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static throwIfPrivateIncludeWithoutUser (include: VideoInclude, user: MUserAccountId) {
|
||||||
|
if (VideoModel.isPrivateInclude(include) && !user?.hasRight(UserRight.SEE_ALL_VIDEOS)) {
|
||||||
|
throw new Error('Try to filter all-local but no user has not the see all videos right')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static isPrivateInclude (include: VideoInclude) {
|
private static isPrivateInclude (include: VideoInclude) {
|
||||||
return include & VideoInclude.BLACKLISTED ||
|
return include & VideoInclude.BLACKLISTED ||
|
||||||
include & VideoInclude.BLOCKED_OWNER ||
|
include & VideoInclude.BLOCKED_OWNER ||
|
||||||
|
|
|
@ -135,6 +135,8 @@ describe('Test videos filter', function () {
|
||||||
server: PeerTubeServer
|
server: PeerTubeServer
|
||||||
path: string
|
path: string
|
||||||
isLocal?: boolean
|
isLocal?: boolean
|
||||||
|
hasWebtorrentFiles?: boolean
|
||||||
|
hasHLSFiles?: boolean
|
||||||
include?: VideoInclude
|
include?: VideoInclude
|
||||||
category?: number
|
category?: number
|
||||||
tagsAllOf?: string[]
|
tagsAllOf?: string[]
|
||||||
|
@ -146,7 +148,7 @@ describe('Test videos filter', function () {
|
||||||
path: options.path,
|
path: options.path,
|
||||||
token: options.token ?? options.server.accessToken,
|
token: options.token ?? options.server.accessToken,
|
||||||
query: {
|
query: {
|
||||||
...pick(options, [ 'isLocal', 'include', 'category', 'tagsAllOf' ]),
|
...pick(options, [ 'isLocal', 'include', 'category', 'tagsAllOf', 'hasWebtorrentFiles', 'hasHLSFiles' ]),
|
||||||
|
|
||||||
sort: 'createdAt'
|
sort: 'createdAt'
|
||||||
},
|
},
|
||||||
|
@ -397,11 +399,9 @@ describe('Test videos filter', function () {
|
||||||
|
|
||||||
for (const path of paths) {
|
for (const path of paths) {
|
||||||
{
|
{
|
||||||
|
|
||||||
const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] })
|
const videos = await listVideos({ server: servers[0], path, tagsAllOf: [ 'tag1', 'tag2' ] })
|
||||||
expect(videos).to.have.lengthOf(1)
|
expect(videos).to.have.lengthOf(1)
|
||||||
expect(videos[0].name).to.equal('tag filter')
|
expect(videos[0].name).to.equal('tag filter')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -421,6 +421,80 @@ describe('Test videos filter', function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Should filter by HLS or WebTorrent files', async function () {
|
||||||
|
this.timeout(360000)
|
||||||
|
|
||||||
|
const finderFactory = (name: string) => (videos: Video[]) => videos.some(v => v.name === name)
|
||||||
|
|
||||||
|
await servers[0].config.enableTranscoding(true, false)
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'webtorrent video' } })
|
||||||
|
const hasWebtorrent = finderFactory('webtorrent video')
|
||||||
|
|
||||||
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
await servers[0].config.enableTranscoding(false, true)
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'hls video' } })
|
||||||
|
const hasHLS = finderFactory('hls video')
|
||||||
|
|
||||||
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
await servers[0].config.enableTranscoding(true, true)
|
||||||
|
await servers[0].videos.upload({ attributes: { name: 'hls and webtorrent video' } })
|
||||||
|
const hasBoth = finderFactory('hls and webtorrent video')
|
||||||
|
|
||||||
|
await waitJobs(servers)
|
||||||
|
|
||||||
|
for (const path of paths) {
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: true })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.true
|
||||||
|
expect(hasHLS(videos)).to.be.false
|
||||||
|
expect(hasBoth(videos)).to.be.true
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasWebtorrentFiles: false })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.false
|
||||||
|
expect(hasHLS(videos)).to.be.true
|
||||||
|
expect(hasBoth(videos)).to.be.false
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.false
|
||||||
|
expect(hasHLS(videos)).to.be.true
|
||||||
|
expect(hasBoth(videos)).to.be.true
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.true
|
||||||
|
expect(hasHLS(videos)).to.be.false
|
||||||
|
expect(hasBoth(videos)).to.be.false
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasHLSFiles: false, hasWebtorrentFiles: false })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.false
|
||||||
|
expect(hasHLS(videos)).to.be.false
|
||||||
|
expect(hasBoth(videos)).to.be.false
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const videos = await listVideos({ server: servers[0], path, hasHLSFiles: true, hasWebtorrentFiles: true })
|
||||||
|
|
||||||
|
expect(hasWebtorrent(videos)).to.be.false
|
||||||
|
expect(hasHLS(videos)).to.be.false
|
||||||
|
expect(hasBoth(videos)).to.be.true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async function () {
|
after(async function () {
|
||||||
|
|
|
@ -26,6 +26,9 @@ export interface VideosCommonQuery {
|
||||||
tagsOneOf?: string[]
|
tagsOneOf?: string[]
|
||||||
tagsAllOf?: string[]
|
tagsAllOf?: string[]
|
||||||
|
|
||||||
|
hasHLSFiles?: boolean
|
||||||
|
hasWebtorrentFiles?: boolean
|
||||||
|
|
||||||
skipCount?: boolean
|
skipCount?: boolean
|
||||||
|
|
||||||
search?: string
|
search?: string
|
||||||
|
|
|
@ -369,6 +369,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
- $ref: '#/components/parameters/skipCount'
|
- $ref: '#/components/parameters/skipCount'
|
||||||
- $ref: '#/components/parameters/start'
|
- $ref: '#/components/parameters/start'
|
||||||
- $ref: '#/components/parameters/count'
|
- $ref: '#/components/parameters/count'
|
||||||
|
@ -1303,6 +1305,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
- $ref: '#/components/parameters/skipCount'
|
- $ref: '#/components/parameters/skipCount'
|
||||||
- $ref: '#/components/parameters/start'
|
- $ref: '#/components/parameters/start'
|
||||||
- $ref: '#/components/parameters/count'
|
- $ref: '#/components/parameters/count'
|
||||||
|
@ -1624,6 +1628,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
- $ref: '#/components/parameters/skipCount'
|
- $ref: '#/components/parameters/skipCount'
|
||||||
- $ref: '#/components/parameters/start'
|
- $ref: '#/components/parameters/start'
|
||||||
- $ref: '#/components/parameters/count'
|
- $ref: '#/components/parameters/count'
|
||||||
|
@ -2861,6 +2867,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
- $ref: '#/components/parameters/skipCount'
|
- $ref: '#/components/parameters/skipCount'
|
||||||
- $ref: '#/components/parameters/start'
|
- $ref: '#/components/parameters/start'
|
||||||
- $ref: '#/components/parameters/count'
|
- $ref: '#/components/parameters/count'
|
||||||
|
@ -3582,6 +3590,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
- $ref: '#/components/parameters/skipCount'
|
- $ref: '#/components/parameters/skipCount'
|
||||||
- $ref: '#/components/parameters/start'
|
- $ref: '#/components/parameters/start'
|
||||||
- $ref: '#/components/parameters/count'
|
- $ref: '#/components/parameters/count'
|
||||||
|
@ -4085,6 +4095,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
responses:
|
responses:
|
||||||
'204':
|
'204':
|
||||||
description: successful operation
|
description: successful operation
|
||||||
|
@ -4167,6 +4179,8 @@ paths:
|
||||||
- $ref: '#/components/parameters/nsfw'
|
- $ref: '#/components/parameters/nsfw'
|
||||||
- $ref: '#/components/parameters/isLocal'
|
- $ref: '#/components/parameters/isLocal'
|
||||||
- $ref: '#/components/parameters/include'
|
- $ref: '#/components/parameters/include'
|
||||||
|
- $ref: '#/components/parameters/hasHLSFiles'
|
||||||
|
- $ref: '#/components/parameters/hasWebtorrentFiles'
|
||||||
responses:
|
responses:
|
||||||
'204':
|
'204':
|
||||||
description: successful operation
|
description: successful operation
|
||||||
|
@ -4806,6 +4820,20 @@ components:
|
||||||
schema:
|
schema:
|
||||||
type: boolean
|
type: boolean
|
||||||
description: '**PeerTube >= 4.0** Display only local or remote videos'
|
description: '**PeerTube >= 4.0** Display only local or remote videos'
|
||||||
|
hasHLSFiles:
|
||||||
|
name: hasHLSFiles
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
description: '**PeerTube >= 4.0** Display only videos that have HLS files'
|
||||||
|
hasWebtorrentFiles:
|
||||||
|
name: hasWebtorrentFiles
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
description: '**PeerTube >= 4.0** Display only videos that have WebTorrent files'
|
||||||
include:
|
include:
|
||||||
name: include
|
name: include
|
||||||
in: query
|
in: query
|
||||||
|
|
Loading…
Reference in a new issue