import { join } from 'path'
import * as Sequelize from 'sequelize'
import {
- AfterDestroy, AllowNull, BeforeDestroy, BelongsTo, BelongsToMany, Column, CreatedAt, DataType, Default, ForeignKey, HasMany,
- IFindOptions, Is, IsInt, IsUUID, Min, Model, Scopes, Table, UpdatedAt
+ AfterDestroy,
+ AllowNull,
+ BeforeDestroy,
+ BelongsTo,
+ BelongsToMany,
+ Column,
+ CreatedAt,
+ DataType,
+ Default,
+ ForeignKey,
+ HasMany,
+ IFindOptions,
+ Is,
+ IsInt,
+ IsUUID,
+ Min,
+ Model,
+ Scopes,
+ Table,
+ UpdatedAt
} from 'sequelize-typescript'
import { VideoPrivacy, VideoResolution } from '../../../shared'
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
import { isBooleanValid } from '../../helpers/custom-validators/misc'
import {
- isVideoCategoryValid, isVideoDescriptionValid, isVideoDurationValid, isVideoLanguageValid, isVideoLicenceValid, isVideoNameValid,
+ isVideoCategoryValid,
+ isVideoDescriptionValid,
+ isVideoDurationValid,
+ isVideoLanguageValid,
+ isVideoLicenceValid,
+ isVideoNameValid,
isVideoPrivacyValid
} from '../../helpers/custom-validators/videos'
import { generateImageFromVideoFile, getVideoFileHeight, transcode } from '../../helpers/ffmpeg-utils'
import { logger } from '../../helpers/logger'
import { getServerActor } from '../../helpers/utils'
import {
- API_VERSION, CONFIG, CONSTRAINTS_FIELDS, PREVIEWS_SIZE, REMOTE_SCHEME, STATIC_PATHS, THUMBNAILS_SIZE, VIDEO_CATEGORIES,
- VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_PRIVACIES
+ API_VERSION,
+ CONFIG,
+ CONSTRAINTS_FIELDS,
+ PREVIEWS_SIZE,
+ REMOTE_SCHEME,
+ STATIC_PATHS,
+ THUMBNAILS_SIZE,
+ VIDEO_CATEGORIES,
+ VIDEO_LANGUAGES,
+ VIDEO_LICENCES,
+ VIDEO_PRIVACIES
} from '../../initializers'
-import { getAnnounceActivityPubUrl } from '../../lib/activitypub'
+import {
+ getVideoCommentsActivityPubUrl,
+ getVideoDislikesActivityPubUrl,
+ getVideoLikesActivityPubUrl,
+ getVideoSharesActivityPubUrl
+} from '../../lib/activitypub'
import { sendDeleteVideo } from '../../lib/activitypub/send'
import { AccountModel } from '../account/account'
import { AccountVideoRateModel } from '../account/account-video-rate'
import { ActorModel } from '../activitypub/actor'
-import { ActorFollowModel } from '../activitypub/actor-follow'
import { ServerModel } from '../server/server'
import { getSort, throwIfNotValid } from '../utils'
import { TagModel } from './tag'
@Scopes({
[ScopeNames.AVAILABLE_FOR_LIST]: (actorId: number) => ({
- subQuery: false,
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) +
+ ' UNION ' +
+ 'SELECT "video"."id" AS "id" FROM "video" ' +
+ 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
+ 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
+ '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,
- [Sequelize.Op.or]: [
- {
- '$VideoChannel.Account.Actor.serverId$': null
- },
- {
- '$VideoChannel.Account.Actor.ActorFollowers.actorId$': actorId
- },
- {
- id: {
- [ Sequelize.Op.in ]: Sequelize.literal(
- '(' +
- 'SELECT "videoShare"."videoId" FROM "videoShare" ' +
- 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
- 'WHERE "actorFollow"."actorId" = ' + parseInt(actorId.toString(), 10) +
- ')'
- )
- }
- }
- ]
+ privacy: VideoPrivacy.PUBLIC
},
include: [
{
include: [
{
attributes: [ 'host' ],
- model: ServerModel.unscoped(),
- required: false
- },
- {
- attributes: [ ],
- model: ActorFollowModel.unscoped(),
- as: 'ActorFollowers',
- required: false
+ model: ServerModel.unscoped()
}
]
}
attributes: {
exclude: [ 'privateKey', 'publicKey' ]
},
- model: () => ActorModel,
- required: true
+ model: () => ActorModel.unscoped(),
+ required: true,
+ include: [
+ {
+ attributes: [ 'host' ],
+ model: () => ServerModel.unscoped(),
+ required: false
+ }
+ ]
},
{
- model: () => AccountModel,
+ model: () => AccountModel.unscoped(),
required: true,
include: [
{
- model: () => ActorModel,
+ model: () => ActorModel.unscoped(),
attributes: {
exclude: [ 'privateKey', 'publicKey' ]
},
required: true,
include: [
{
- model: () => ServerModel,
+ attributes: [ 'host' ],
+ model: () => ServerModel.unscoped(),
required: false
}
]
where: {
id: {
[Sequelize.Op.in]: Sequelize.literal('(' + rawQuery + ')')
- }
+ },
+ [Sequelize.Op.or]: [
+ { privacy: VideoPrivacy.PUBLIC },
+ { privacy: VideoPrivacy.UNLISTED }
+ ]
},
include: [
{
- attributes: [ 'id' ],
+ attributes: [ 'id', 'url' ],
model: VideoShareModel.unscoped(),
required: false,
where: {
createTorrentAndSetInfoHash = async function (videoFile: VideoFileModel) {
const options = {
announceList: [
- [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ]
+ [ CONFIG.WEBSERVER.WS + '://' + CONFIG.WEBSERVER.HOSTNAME + ':' + CONFIG.WEBSERVER.PORT + '/tracker/socket' ],
+ [ CONFIG.WEBSERVER.URL + '/tracker/announce' ]
],
urlList: [
CONFIG.WEBSERVER.URL + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile)
}
}
- likesObject = activityPubCollection(likes)
- dislikesObject = activityPubCollection(dislikes)
+ const res = this.toRatesActivityPubObjects()
+ likesObject = res.likesObject
+ dislikesObject = res.dislikesObject
}
let sharesObject
if (Array.isArray(this.VideoShares)) {
- const shares: string[] = []
-
- for (const videoShare of this.VideoShares) {
- const shareUrl = getAnnounceActivityPubUrl(this.url, videoShare.Actor)
- shares.push(shareUrl)
- }
-
- sharesObject = activityPubCollection(shares)
+ sharesObject = this.toAnnouncesActivityPubObject()
}
let commentsObject
if (Array.isArray(this.VideoComments)) {
- const comments: string[] = []
-
- for (const videoComment of this.VideoComments) {
- comments.push(videoComment.url)
- }
-
- commentsObject = activityPubCollection(comments)
+ commentsObject = this.toCommentsActivityPubObject()
}
const url = []
type: 'Video' as 'Video',
id: this.url,
name: this.name,
- // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
- duration: 'PT' + this.duration + 'S',
+ duration: this.getActivityStreamDuration(),
uuid: this.uuid,
tag,
category,
licence,
language,
views: this.views,
- nsfw: this.nsfw,
+ sensitive: this.nsfw,
commentsEnabled: this.commentsEnabled,
published: this.createdAt.toISOString(),
updated: this.updatedAt.toISOString(),
}
}
+ toAnnouncesActivityPubObject () {
+ const shares: string[] = []
+
+ for (const videoShare of this.VideoShares) {
+ shares.push(videoShare.url)
+ }
+
+ return activityPubCollection(getVideoSharesActivityPubUrl(this), shares)
+ }
+
+ toCommentsActivityPubObject () {
+ const comments: string[] = []
+
+ for (const videoComment of this.VideoComments) {
+ comments.push(videoComment.url)
+ }
+
+ return activityPubCollection(getVideoCommentsActivityPubUrl(this), comments)
+ }
+
+ toRatesActivityPubObjects () {
+ const likes: string[] = []
+ const dislikes: string[] = []
+
+ for (const rate of this.AccountVideoRates) {
+ if (rate.type === 'like') {
+ likes.push(rate.Account.Actor.url)
+ } else if (rate.type === 'dislike') {
+ dislikes.push(rate.Account.Actor.url)
+ }
+ }
+
+ const likesObject = activityPubCollection(getVideoLikesActivityPubUrl(this), likes)
+ const dislikesObject = activityPubCollection(getVideoDislikesActivityPubUrl(this), dislikes)
+
+ return { likesObject, dislikesObject }
+ }
+
getTruncatedDescription () {
if (!this.description) return null
return unlinkPromise(torrentPath)
}
+ getActivityStreamDuration () {
+ // https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
+ return 'PT' + this.duration + 'S'
+ }
+
private getBaseUrls () {
let baseUrlHttp
let baseUrlWs