} from 'sequelize-typescript'
import { VideoPrivacy, VideoResolution } from '../../../shared'
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
-import { Video, VideoDetails } from '../../../shared/models/videos'
+import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos'
import { VideoFilter } from '../../../shared/models/videos/video-query.type'
import { activityPubCollection } from '../../helpers/activitypub'
import {
}
@Scopes({
- [ScopeNames.AVAILABLE_FOR_LIST]: (actorId: number, filter?: VideoFilter) => ({
- where: {
- id: {
- [Sequelize.Op.notIn]: Sequelize.literal(
- '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
- ),
- [ Sequelize.Op.in ]: Sequelize.literal(
- '(' +
+ [ScopeNames.AVAILABLE_FOR_LIST]: (actorId: number, hideNSFW: boolean, filter?: VideoFilter, withFiles?: boolean) => {
+ const query: IFindOptions<VideoModel> = {
+ where: {
+ id: {
+ [Sequelize.Op.notIn]: Sequelize.literal(
+ '(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
+ ),
+ [ Sequelize.Op.in ]: Sequelize.literal(
+ '(' +
'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
'WHERE "actorFollow"."actorId" = ' + parseInt(actorId.toString(), 10) +
'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
'LEFT JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
'WHERE "actor"."serverId" IS NULL OR "actorFollow"."actorId" = ' + parseInt(actorId.toString(), 10) +
- ')'
- )
+ ')'
+ )
+ },
+ privacy: VideoPrivacy.PUBLIC
},
- privacy: VideoPrivacy.PUBLIC
- },
- include: [
- {
- attributes: [ 'name', 'description' ],
- model: VideoChannelModel.unscoped(),
- required: true,
- include: [
- {
- attributes: [ 'name' ],
- model: AccountModel.unscoped(),
- required: true,
- include: [
- {
- attributes: [ 'preferredUsername', 'url', 'serverId' ],
- model: ActorModel.unscoped(),
- required: true,
- where: VideoModel.buildActorWhereWithFilter(filter),
- include: [
- {
- attributes: [ 'host' ],
- model: ServerModel.unscoped(),
- required: false
- },
- {
- model: AvatarModel.unscoped(),
- required: false
- }
- ]
- }
- ]
- }
- ]
- }
- ]
- }),
+ include: [
+ {
+ attributes: [ 'name', 'description' ],
+ model: VideoChannelModel.unscoped(),
+ required: true,
+ include: [
+ {
+ attributes: [ 'name' ],
+ model: AccountModel.unscoped(),
+ required: true,
+ include: [
+ {
+ attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ],
+ model: ActorModel.unscoped(),
+ required: true,
+ where: VideoModel.buildActorWhereWithFilter(filter),
+ include: [
+ {
+ attributes: [ 'host' ],
+ model: ServerModel.unscoped(),
+ required: false
+ },
+ {
+ model: AvatarModel.unscoped(),
+ required: false
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ ]
+ }
+
+ if (withFiles === true) {
+ query.include.push({
+ model: VideoFileModel.unscoped(),
+ required: true
+ })
+ }
+
+ // Hide nsfw videos?
+ if (hideNSFW === true) {
+ query.where['nsfw'] = false
+ }
+
+ return query
+ },
[ScopeNames.WITH_ACCOUNT_DETAILS]: {
include: [
{
@AllowNull(true)
@Default(null)
@Is('VideoLanguage', value => throwIfNotValid(value, isVideoLanguageValid, 'language'))
- @Column
- language: number
+ @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEOS.LANGUAGE.max))
+ language: string
@AllowNull(false)
@Is('VideoPrivacy', value => throwIfNotValid(value, isVideoPrivacyValid, 'privacy'))
})
}
- static listUserVideosForApi (userId: number, start: number, count: number, sort: string) {
- const query = {
+ static listAccountVideosForApi (accountId: number, start: number, count: number, sort: string, hideNSFW: boolean, withFiles = false) {
+ const query: IFindOptions<VideoModel> = {
offset: start,
limit: count,
order: getSort(sort),
{
model: AccountModel,
where: {
- userId
+ id: accountId
},
required: true
}
]
}
+ if (withFiles === true) {
+ query.include.push({
+ model: VideoFileModel.unscoped(),
+ required: true
+ })
+ }
+
+ if (hideNSFW === true) {
+ query.where = {
+ nsfw: false
+ }
+ }
+
return VideoModel.findAndCountAll(query).then(({ rows, count }) => {
return {
data: rows,
})
}
- static async listForApi (start: number, count: number, sort: string, filter?: VideoFilter) {
+ static async listForApi (start: number, count: number, sort: string, hideNSFW: boolean, filter?: VideoFilter, withFiles = false) {
const query = {
offset: start,
limit: count,
}
const serverActor = await getServerActor()
-
- return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, filter ] })
+ return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, hideNSFW, filter, withFiles ] })
.findAndCountAll(query)
.then(({ rows, count }) => {
return {
})
}
- static async searchAndPopulateAccountAndServerAndTags (value: string, start: number, count: number, sort: string) {
+ static async searchAndPopulateAccountAndServer (value: string, start: number, count: number, sort: string, hideNSFW: boolean) {
const query: IFindOptions<VideoModel> = {
offset: start,
limit: count,
const serverActor = await getServerActor()
- return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id ] })
- .findAndCountAll(query).then(({ rows, count }) => {
+ return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST, serverActor.id, hideNSFW ] })
+ .findAndCountAll(query)
+ .then(({ rows, count }) => {
return {
data: rows,
total: count
return licenceLabel
}
- private static getLanguageLabel (id: number) {
+ private static getLanguageLabel (id: string) {
let languageLabel = VIDEO_LANGUAGES[id]
+ console.log(VIDEO_LANGUAGES)
+ console.log(id)
if (!languageLabel) languageLabel = 'Unknown'
return languageLabel
}
+ private static getPrivacyLabel (id: number) {
+ let privacyLabel = VIDEO_PRIVACIES[id]
+ if (!privacyLabel) privacyLabel = 'Unknown'
+
+ return privacyLabel
+ }
+
getOriginalFile () {
if (Array.isArray(this.VideoFiles) === false) return undefined
return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile))
}
- createTorrentAndSetInfoHash = async function (videoFile: VideoFileModel) {
+ async createTorrentAndSetInfoHash (videoFile: VideoFileModel) {
const options = {
+ // Keep the extname, it's used by the client to stream the file inside a web browser
+ name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`,
+ createdBy: 'PeerTube',
announceList: [
[ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ],
[ CONFIG.WEBSERVER.URL + '/tracker/announce' ]
id: this.language,
label: VideoModel.getLanguageLabel(this.language)
},
+ privacy: {
+ id: this.privacy,
+ label: VideoModel.getPrivacyLabel(this.privacy)
+ },
nsfw: this.nsfw,
description: this.getTruncatedDescription(),
isLocal: this.isOwned(),
toFormattedDetailsJSON (): VideoDetails {
const formattedJson = this.toFormattedJSON()
- // Maybe our server is not up to date and there are new privacy settings since our version
- let privacyLabel = VIDEO_PRIVACIES[this.privacy]
- if (!privacyLabel) privacyLabel = 'Unknown'
-
const detailsJson = {
- privacy: {
- id: this.privacy,
- label: privacyLabel
- },
support: this.support,
descriptionPath: this.getDescriptionPath(),
channel: this.VideoChannel.toFormattedJSON(),
account: this.VideoChannel.Account.toFormattedJSON(),
- tags: map<TagModel, string>(this.Tags, 'name'),
+ tags: map(this.Tags, 'name'),
commentsEnabled: this.commentsEnabled,
files: []
}
// Format and sort video files
+ detailsJson.files = this.getFormattedVideoFilesJSON()
+
+ return Object.assign(formattedJson, detailsJson)
+ }
+
+ getFormattedVideoFilesJSON (): VideoFile[] {
const { baseUrlHttp, baseUrlWs } = this.getBaseUrls()
- detailsJson.files = this.VideoFiles
- .map(videoFile => {
- let resolutionLabel = videoFile.resolution + 'p'
- return {
- resolution: {
- id: videoFile.resolution,
- label: resolutionLabel
- },
- magnetUri: this.generateMagnetUri(videoFile, baseUrlHttp, baseUrlWs),
- size: videoFile.size,
- torrentUrl: this.getTorrentUrl(videoFile, baseUrlHttp),
- fileUrl: this.getVideoFileUrl(videoFile, baseUrlHttp)
- }
- })
- .sort((a, b) => {
- if (a.resolution.id < b.resolution.id) return 1
- if (a.resolution.id === b.resolution.id) return 0
- return -1
- })
+ return this.VideoFiles
+ .map(videoFile => {
+ let resolutionLabel = videoFile.resolution + 'p'
- return Object.assign(formattedJson, detailsJson)
+ return {
+ resolution: {
+ id: videoFile.resolution,
+ label: resolutionLabel
+ },
+ magnetUri: this.generateMagnetUri(videoFile, baseUrlHttp, baseUrlWs),
+ size: videoFile.size,
+ torrentUrl: this.getTorrentUrl(videoFile, baseUrlHttp),
+ fileUrl: this.getVideoFileUrl(videoFile, baseUrlHttp)
+ } as VideoFile
+ })
+ .sort((a, b) => {
+ if (a.resolution.id < b.resolution.id) return 1
+ if (a.resolution.id === b.resolution.id) return 0
+ return -1
+ })
}
toActivityPubObject (): VideoTorrentObject {
let language
if (this.language) {
language = {
- identifier: this.language + '',
+ identifier: this.language,
name: VideoModel.getLanguageLabel(this.language)
}
}
return peertubeTruncate(this.description, maxLength)
}
- optimizeOriginalVideofile = async function () {
+ async optimizeOriginalVideofile () {
const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
const newExtname = '.mp4'
const inputVideoFile = this.getOriginalFile()
}
}
- transcodeOriginalVideofile = async function (resolution: VideoResolution, isPortraitMode: boolean) {
+ async transcodeOriginalVideofile (resolution: VideoResolution, isPortraitMode: boolean) {
const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
const extname = '.mp4'