- VideoInstance,
- VideoAttributes,
-
- VideoMethods
-} from './video-interface'
-
-let Video: Sequelize.Model<VideoInstance, VideoAttributes>
-let generateMagnetUri: VideoMethods.GenerateMagnetUri
-let getVideoFilename: VideoMethods.GetVideoFilename
-let getThumbnailName: VideoMethods.GetThumbnailName
-let getPreviewName: VideoMethods.GetPreviewName
-let getTorrentName: VideoMethods.GetTorrentName
-let isOwned: VideoMethods.IsOwned
-let toFormatedJSON: VideoMethods.ToFormatedJSON
-let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON
-let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON
-let transcodeVideofile: VideoMethods.TranscodeVideofile
-
-let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
-let getDurationFromFile: VideoMethods.GetDurationFromFile
-let list: VideoMethods.List
-let listForApi: VideoMethods.ListForApi
-let loadByHostAndUUID: VideoMethods.LoadByHostAndUUID
-let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
-let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor
-let load: VideoMethods.Load
-let loadByUUID: VideoMethods.LoadByUUID
-let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor
-let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags
-let loadByUUIDAndPopulateAuthorAndPodAndTags: VideoMethods.LoadByUUIDAndPopulateAuthorAndPodAndTags
-let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags
-
-export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
- Video = sequelize.define<VideoInstance, VideoAttributes>('Video',
- {
- uuid: {
- type: DataTypes.UUID,
- defaultValue: DataTypes.UUIDV4,
- allowNull: false,
- validate: {
- isUUID: 4
- }
- },
- name: {
- type: DataTypes.STRING,
- allowNull: false,
- validate: {
- nameValid: function (value) {
- const res = isVideoNameValid(value)
- if (res === false) throw new Error('Video name is not valid.')
- }
- }
- },
- extname: {
- type: DataTypes.ENUM(values(CONSTRAINTS_FIELDS.VIDEOS.EXTNAME)),
- allowNull: false
- },
- category: {
- type: DataTypes.INTEGER,
- allowNull: false,
- validate: {
- categoryValid: function (value) {
- const res = isVideoCategoryValid(value)
- if (res === false) throw new Error('Video category is not valid.')
- }
- }
- },
- licence: {
- type: DataTypes.INTEGER,
- allowNull: false,
- defaultValue: null,
- validate: {
- licenceValid: function (value) {
- const res = isVideoLicenceValid(value)
- if (res === false) throw new Error('Video licence is not valid.')
- }
- }
- },
- language: {
- type: DataTypes.INTEGER,
- allowNull: true,
- validate: {
- languageValid: function (value) {
- const res = isVideoLanguageValid(value)
- if (res === false) throw new Error('Video language is not valid.')
- }
- }
- },
- nsfw: {
- type: DataTypes.BOOLEAN,
- allowNull: false,
- validate: {
- nsfwValid: function (value) {
- const res = isVideoNSFWValid(value)
- if (res === false) throw new Error('Video nsfw attribute is not valid.')
- }
+ videoFilesModelToFormattedJSON,
+ VideoFormattingJSONOptions,
+ videoModelToActivityPubObject,
+ videoModelToFormattedDetailsJSON,
+ videoModelToFormattedJSON
+} from './video-format-utils'
+import * as validator from 'validator'
+import { UserVideoHistoryModel } from '../account/user-video-history'
+import { UserModel } from '../account/user'
+
+// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
+const indexes: Sequelize.DefineIndexesOptions[] = [
+ buildTrigramSearchIndex('video_name_trigram', 'name'),
+
+ { fields: [ 'createdAt' ] },
+ { fields: [ 'publishedAt' ] },
+ { fields: [ 'duration' ] },
+ { fields: [ 'category' ] },
+ { fields: [ 'licence' ] },
+ { fields: [ 'nsfw' ] },
+ { fields: [ 'language' ] },
+ { fields: [ 'waitTranscoding' ] },
+ { fields: [ 'state' ] },
+ { fields: [ 'remote' ] },
+ { fields: [ 'views' ] },
+ { fields: [ 'likes' ] },
+ { fields: [ 'channelId' ] },
+ {
+ fields: [ 'uuid' ],
+ unique: true
+ },
+ {
+ fields: [ 'url' ],
+ unique: true
+ }
+]
+
+export enum ScopeNames {
+ AVAILABLE_FOR_LIST_IDS = 'AVAILABLE_FOR_LIST_IDS',
+ FOR_API = 'FOR_API',
+ WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS',
+ WITH_TAGS = 'WITH_TAGS',
+ WITH_FILES = 'WITH_FILES',
+ WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE',
+ WITH_BLACKLISTED = 'WITH_BLACKLISTED',
+ WITH_USER_HISTORY = 'WITH_USER_HISTORY'
+}
+
+type ForAPIOptions = {
+ ids: number[]
+ withFiles?: boolean
+}
+
+type AvailableForListIDsOptions = {
+ serverAccountId: number
+ actorId: number
+ includeLocalVideos: boolean
+ filter?: VideoFilter
+ categoryOneOf?: number[]
+ nsfw?: boolean
+ licenceOneOf?: number[]
+ languageOneOf?: string[]
+ tagsOneOf?: string[]
+ tagsAllOf?: string[]
+ withFiles?: boolean
+ accountId?: number
+ videoChannelId?: number
+ trendingDays?: number
+ user?: UserModel
+}
+
+@Scopes({
+ [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
+ const accountInclude = {
+ attributes: [ 'id', 'name' ],
+ model: AccountModel.unscoped(),
+ required: true,
+ include: [
+ {
+ attributes: [ 'id', 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
+ model: ActorModel.unscoped(),
+ required: true,
+ include: [
+ {
+ attributes: [ 'host' ],
+ model: ServerModel.unscoped(),
+ required: false
+ },
+ {
+ model: AvatarModel.unscoped(),
+ required: false
+ }
+ ]