UpdatedAt
} from 'sequelize-typescript'
import { buildNSFWFilter } from '@server/helpers/express-utils'
-import { uuidToShort } from '@server/helpers/uuid'
import { getPrivaciesForFederation, isPrivacyForFederation, isStateForFederation } from '@server/helpers/video'
import { LiveManager } from '@server/lib/live/live-manager'
import { removeHLSObjectStorage, removeWebTorrentObjectStorage } from '@server/lib/object-storage'
import { VideoPathManager } from '@server/lib/video-path-manager'
import { getServerActor } from '@server/models/application/application'
import { ModelCache } from '@server/models/model-cache'
-import { AttributesOnly, buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils'
-import { VideoInclude } from '@shared/models'
-import { VideoFile } from '@shared/models/videos/video-file.model'
-import { ResultList, UserRight, VideoPrivacy, VideoState } from '../../../shared'
-import { VideoObject } from '../../../shared/models/activitypub/objects'
-import { Video, VideoDetails, VideoRateType, VideoStorage } from '../../../shared/models/videos'
-import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
-import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
+import { buildVideoEmbedPath, buildVideoWatchPath, pick } from '@shared/core-utils'
+import { ffprobePromise, getAudioStream, uuidToShort } from '@shared/extra-utils'
+import {
+ ResultList,
+ ThumbnailType,
+ UserRight,
+ Video,
+ VideoDetails,
+ VideoFile,
+ VideoInclude,
+ VideoObject,
+ VideoPrivacy,
+ VideoRateType,
+ VideoState,
+ VideoStorage,
+ VideoStreamingPlaylistType
+} from '@shared/models'
+import { AttributesOnly } from '@shared/typescript-utils'
import { peertubeTruncate } from '../../helpers/core-utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { exists, isBooleanValid } from '../../helpers/custom-validators/misc'
isVideoStateValid,
isVideoSupportValid
} from '../../helpers/custom-validators/videos'
-import { getVideoFileResolution } from '../../helpers/ffprobe-utils'
+import { getVideoStreamDimensionsInfo } from '../../helpers/ffmpeg'
import { logger } from '../../helpers/logger'
import { CONFIG } from '../../initializers/config'
import { ACTIVITY_PUB, API_VERSION, CONSTRAINTS_FIELDS, LAZY_STATIC_PATHS, STATIC_PATHS, WEBSERVER } from '../../initializers/constants'
videoModelToFormattedJSON
} from './formatter/video-format-utils'
import { ScheduleVideoUpdateModel } from './schedule-video-update'
-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 {
+ BuildVideosListQueryOptions,
+ DisplayOnlyForFollowerOptions,
+ VideoModelGetQueryBuilder,
+ VideosIdListQueryBuilder,
+ VideosModelListQueryBuilder
+} from './sql/video'
import { TagModel } from './tag'
import { ThumbnailModel } from './thumbnail'
import { VideoBlacklistModel } from './video-blacklist'
required: false
},
{
- model: ActorImageModel.unscoped(),
- as: 'Avatar',
+ model: ActorImageModel,
+ as: 'Avatars',
required: false
}
]
required: false
},
{
- model: ActorImageModel.unscoped(),
- as: 'Avatar',
+ model: ActorImageModel,
+ as: 'Avatars',
required: false
}
]
// Remove physical files and torrents
instance.VideoFiles.forEach(file => {
- tasks.push(instance.removeFileAndTorrent(file))
+ tasks.push(instance.removeWebTorrentFileAndTorrent(file))
})
// Remove playlists file
languageOneOf?: string[]
tagsOneOf?: string[]
tagsAllOf?: string[]
+ privacyOneOf?: VideoPrivacy[]
accountId?: number
videoChannelId?: number
search?: string
}) {
VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user)
+ VideoModel.throwIfPrivacyOneOfWithoutUser(options.privacyOneOf, options.user)
const trendingDays = options.sort.endsWith('trending')
? CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS
'languageOneOf',
'tagsOneOf',
'tagsAllOf',
+ 'privacyOneOf',
'isLocal',
'include',
'displayOnlyForFollower',
languageOneOf?: string[]
tagsOneOf?: string[]
tagsAllOf?: string[]
+ privacyOneOf?: VideoPrivacy[]
displayOnlyForFollower: DisplayOnlyForFollowerOptions | null
uuids?: string[]
}) {
VideoModel.throwIfPrivateIncludeWithoutUser(options.include, options.user)
+ VideoModel.throwIfPrivacyOneOfWithoutUser(options.privacyOneOf, options.user)
const serverActor = await getServerActor()
'languageOneOf',
'tagsOneOf',
'tagsAllOf',
+ 'privacyOneOf',
'user',
'isLocal',
'host',
required: false,
where: {
startDate: {
- [Op.gte]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
+ // FIXME: ts error
+ [Op.gte as any]: new Date(new Date().getTime() - (24 * 3600 * 1000) * trendingDays)
}
}
}
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')
+ throw new Error('Try to filter all-local but user cannot see all videos')
+ }
+ }
+
+ private static throwIfPrivacyOneOfWithoutUser (privacyOneOf: VideoPrivacy[], user: MUserAccountId) {
+ if (privacyOneOf && !user?.hasRight(UserRight.SEE_ALL_VIDEOS)) {
+ throw new Error('Try to choose video privacies but user cannot see all videos')
}
}
private static isPrivateInclude (include: VideoInclude) {
return include & VideoInclude.BLACKLISTED ||
include & VideoInclude.BLOCKED_OWNER ||
- include & VideoInclude.HIDDEN_PRIVACY ||
include & VideoInclude.NOT_PUBLISHED_STATE
}
return peertubeTruncate(this.description, { length: maxLength })
}
- getMaxQualityResolution () {
+ probeMaxQualityFile () {
const file = this.getMaxQualityFile()
const videoOrPlaylist = file.getVideoOrStreamingPlaylist()
- return VideoPathManager.Instance.makeAvailableVideoFile(videoOrPlaylist, file, originalFilePath => {
- return getVideoFileResolution(originalFilePath)
+ return VideoPathManager.Instance.makeAvailableVideoFile(file.withVideoOrPlaylist(videoOrPlaylist), async originalFilePath => {
+ const probe = await ffprobePromise(originalFilePath)
+
+ const { audioStream } = await getAudioStream(originalFilePath, probe)
+
+ return {
+ audioStream,
+
+ ...await getVideoStreamDimensionsInfo(originalFilePath, probe)
+ }
})
}
.concat(toAdd)
}
- removeFileAndTorrent (videoFile: MVideoFile, isRedundancy = false) {
+ removeWebTorrentFileAndTorrent (videoFile: MVideoFile, isRedundancy = false) {
const filePath = isRedundancy
? VideoPathManager.Instance.getFSRedundancyVideoFilePath(this, videoFile)
: VideoPathManager.Instance.getFSVideoFileOutputPath(this, videoFile)
)
if (streamingPlaylist.storage === VideoStorage.OBJECT_STORAGE) {
- await removeHLSObjectStorage(streamingPlaylist, this)
+ await removeHLSObjectStorage(streamingPlaylist.withVideo(this))
}
}
}