Table,
UpdatedAt
} from 'sequelize-typescript'
-import { UserRight, VideoPrivacy, VideoState } from '../../../shared'
+import { UserRight, VideoPrivacy, VideoResolution, VideoState } from '../../../shared'
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos'
import { VideoFilter } from '../../../shared/models/videos/video-query.type'
CONSTRAINTS_FIELDS,
HLS_REDUNDANCY_DIRECTORY,
HLS_STREAMING_PLAYLIST_DIRECTORY,
+ LAZY_STATIC_PATHS,
REMOTE_SCHEME,
STATIC_DOWNLOAD_PATHS,
STATIC_PATHS,
} from '../utils'
import { TagModel } from './tag'
import { VideoAbuseModel } from './video-abuse'
-import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel'
+import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
import { VideoCommentModel } from './video-comment'
import { VideoFileModel } from './video-file'
import { VideoShareModel } from './video-share'
WITH_FILES = 'WITH_FILES',
WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE',
WITH_BLACKLISTED = 'WITH_BLACKLISTED',
+ WITH_BLOCKLIST = 'WITH_BLOCKLIST',
WITH_USER_HISTORY = 'WITH_USER_HISTORY',
WITH_STREAMING_PLAYLISTS = 'WITH_STREAMING_PLAYLISTS',
WITH_USER_ID = 'WITH_USER_ID',
WITH_THUMBNAILS = 'WITH_THUMBNAILS'
}
-type ForAPIOptions = {
- ids: number[]
+export type ForAPIOptions = {
+ ids?: number[]
videoPlaylistId?: number
withFiles?: boolean
+
+ withAccountBlockerIds?: number[]
}
-type AvailableForListIDsOptions = {
+export type AvailableForListIDsOptions = {
serverAccountId: number
followerActorId: number
includeLocalVideos: boolean
- withoutId?: boolean
+ attributesType?: 'none' | 'id' | 'all'
filter?: VideoFilter
categoryOneOf?: number[]
@Scopes(() => ({
[ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
const query: FindOptions = {
- where: {
- id: {
- [ Op.in ]: options.ids // FIXME: sequelize ANY seems broken
- }
- },
include: [
{
- model: VideoChannelModel.scope({ method: [ VideoChannelScopeNames.SUMMARY, true ] }),
+ model: VideoChannelModel.scope({
+ method: [
+ VideoChannelScopeNames.SUMMARY, {
+ withAccount: true,
+ withAccountBlockerIds: options.withAccountBlockerIds
+ } as SummaryOptions
+ ]
+ }),
required: true
},
{
]
}
+ if (options.ids) {
+ query.where = {
+ id: {
+ [ Op.in ]: options.ids // FIXME: sequelize ANY seems broken
+ }
+ }
+ }
+
if (options.withFiles === true) {
query.include.push({
model: VideoFileModel.unscoped(),
const query: FindOptions = {
raw: true,
- attributes: options.withoutId === true ? [] : [ 'id' ],
include: []
}
+ const attributesType = options.attributesType || 'id'
+
+ if (attributesType === 'id') query.attributes = [ 'id' ]
+ else if (attributesType === 'none') query.attributes = [ ]
+
whereAnd.push({
id: {
[ Op.notIn ]: Sequelize.literal(
}
})
- whereAnd.push({
- channelId: {
- [ Op.notIn ]: Sequelize.literal(
- '(' +
- 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' +
- buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) +
- ')' +
- ')'
- )
- }
- })
+ if (options.serverAccountId) {
+ whereAnd.push({
+ channelId: {
+ [ Op.notIn ]: Sequelize.literal(
+ '(' +
+ 'SELECT id FROM "videoChannel" WHERE "accountId" IN (' +
+ buildBlockedAccountSQL(options.serverAccountId, options.user ? options.user.Account.id : undefined) +
+ ')' +
+ ')'
+ )
+ }
+ })
+ }
// Only list public/published videos
if (!options.filter || options.filter !== 'all-local') {
}
return query
+ },
+ [ScopeNames.WITH_BLOCKLIST]: {
+
},
[ ScopeNames.WITH_THUMBNAILS ]: {
include: [
@HasMany(() => VideoPlaylistElementModel, {
foreignKey: {
name: 'videoId',
- allowNull: false
+ allowNull: true
},
- onDelete: 'cascade'
+ onDelete: 'set null'
})
VideoPlaylistElements: VideoPlaylistElementModel[]
serverAccountId: serverActor.Account.id,
followerActorId,
includeLocalVideos: true,
- withoutId: true // Don't break aggregation
+ attributesType: 'none' // Don't break aggregation
}
const query: FindOptions = {
return VIDEO_STATES[ id ] || 'Unknown'
}
+ isBlacklisted () {
+ return !!this.VideoBlacklist
+ }
+
+ isBlocked () {
+ return (this.VideoChannel.Account.Actor.Server && this.VideoChannel.Account.Actor.Server.isBlocked()) ||
+ this.VideoChannel.Account.isBlocked()
+ }
+
getOriginalFile () {
if (Array.isArray(this.VideoFiles) === false) return undefined
return maxBy(this.VideoFiles, file => file.resolution)
}
+ getFile (resolution: VideoResolution) {
+ if (Array.isArray(this.VideoFiles) === false) return undefined
+
+ return this.VideoFiles.find(f => f.resolution === resolution)
+ }
+
async addAndSaveThumbnail (thumbnail: ThumbnailModel, transaction: Transaction) {
thumbnail.videoId = this.id
if (!preview) return null
// We use a local cache, so specify our cache endpoint instead of potential remote URL
- return join(STATIC_PATHS.PREVIEWS, preview.filename)
+ return join(LAZY_STATIC_PATHS.PREVIEWS, preview.filename)
}
toFormattedJSON (options?: VideoFormattingJSONOptions): Video {