]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/video/video-file.ts
Add lazy loading in player
[github/Chocobozzz/PeerTube.git] / server / models / video / video-file.ts
index 09a30d7e0c1b206fb55fe5f15cd3cf2806079ad0..1f1b76c1e10e0621dffe5ef18af13c64fa07747f 100644 (file)
-import * as Sequelize from 'sequelize'
-import { values } from 'lodash'
-
-import { CONSTRAINTS_FIELDS } from '../../initializers'
 import {
+  AllowNull,
+  BelongsTo,
+  Column,
+  CreatedAt,
+  DataType,
+  Default,
+  ForeignKey,
+  HasMany,
+  Is,
+  Model,
+  Table,
+  UpdatedAt
+} from 'sequelize-typescript'
+import {
+  isVideoFileExtnameValid,
+  isVideoFileInfoHashValid,
   isVideoFileResolutionValid,
   isVideoFileSizeValid,
-  isVideoFileInfoHashValid
-} from '../../helpers'
-
-import { addMethodsToModel } from '../utils'
-import {
-  VideoFileInstance,
-  VideoFileAttributes
-} from './video-file-interface'
-
-let VideoFile: Sequelize.Model<VideoFileInstance, VideoFileAttributes>
+  isVideoFPSResolutionValid
+} from '../../helpers/custom-validators/videos'
+import { throwIfNotValid } from '../utils'
+import { VideoModel } from './video'
+import * as Sequelize from 'sequelize'
+import { VideoRedundancyModel } from '../redundancy/video-redundancy'
 
-export default function (sequelize: Sequelize.Sequelize, DataTypes: Sequelize.DataTypes) {
-  VideoFile = sequelize.define<VideoFileInstance, VideoFileAttributes>('VideoFile',
+@Table({
+  tableName: 'videoFile',
+  indexes: [
     {
-      resolution: {
-        type: DataTypes.INTEGER,
-        allowNull: false,
-        validate: {
-          resolutionValid: value => {
-            const res = isVideoFileResolutionValid(value)
-            if (res === false) throw new Error('Video file resolution is not valid.')
-          }
-        }
-      },
-      size: {
-        type: DataTypes.INTEGER,
-        allowNull: false,
-        validate: {
-          sizeValid: value => {
-            const res = isVideoFileSizeValid(value)
-            if (res === false) throw new Error('Video file size is not valid.')
-          }
-        }
-      },
-      extname: {
-        type: DataTypes.ENUM(values(CONSTRAINTS_FIELDS.VIDEOS.EXTNAME)),
-        allowNull: false
-      },
-      infoHash: {
-        type: DataTypes.STRING,
-        allowNull: false,
-        validate: {
-          infoHashValid: value => {
-            const res = isVideoFileInfoHashValid(value)
-            if (res === false) throw new Error('Video file info hash is not valid.')
-          }
-        }
-      }
+      fields: [ 'videoId' ]
     },
     {
-      indexes: [
-        {
-          fields: [ 'videoId' ]
-        },
-        {
-          fields: [ 'infoHash' ]
-        }
-      ]
+      fields: [ 'infoHash' ]
+    },
+    {
+      fields: [ 'videoId', 'resolution', 'fps' ],
+      unique: true
     }
-  )
-
-  const classMethods = [
-    associate
   ]
-  addMethodsToModel(VideoFile, classMethods)
+})
+export class VideoFileModel extends Model<VideoFileModel> {
+  @CreatedAt
+  createdAt: Date
 
-  return VideoFile
-}
+  @UpdatedAt
+  updatedAt: Date
+
+  @AllowNull(false)
+  @Is('VideoFileResolution', value => throwIfNotValid(value, isVideoFileResolutionValid, 'resolution'))
+  @Column
+  resolution: number
+
+  @AllowNull(false)
+  @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileSizeValid, 'size'))
+  @Column(DataType.BIGINT)
+  size: number
+
+  @AllowNull(false)
+  @Is('VideoFileExtname', value => throwIfNotValid(value, isVideoFileExtnameValid, 'extname'))
+  @Column
+  extname: string
+
+  @AllowNull(false)
+  @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash'))
+  @Column
+  infoHash: string
 
-// ------------------------------ STATICS ------------------------------
+  @AllowNull(false)
+  @Default(-1)
+  @Is('VideoFileFPS', value => throwIfNotValid(value, isVideoFPSResolutionValid, 'fps'))
+  @Column
+  fps: number
 
-function associate (models) {
-  VideoFile.belongsTo(models.Video, {
+  @ForeignKey(() => VideoModel)
+  @Column
+  videoId: number
+
+  @BelongsTo(() => VideoModel, {
     foreignKey: {
-      name: 'videoId',
       allowNull: false
     },
     onDelete: 'CASCADE'
   })
-}
+  Video: VideoModel
+
+  @HasMany(() => VideoRedundancyModel, {
+    foreignKey: {
+      allowNull: false
+    },
+    onDelete: 'CASCADE',
+    hooks: true
+  })
+  RedundancyVideos: VideoRedundancyModel[]
+
+  static isInfohashExists (infoHash: string) {
+    const query = 'SELECT 1 FROM "videoFile" WHERE "infoHash" = $infoHash LIMIT 1'
+    const options = {
+      type: Sequelize.QueryTypes.SELECT,
+      bind: { infoHash },
+      raw: true
+    }
+
+    return VideoModel.sequelize.query(query, options)
+              .then(results => {
+                return results.length === 1
+              })
+  }
+
+  static loadWithVideo (id: number) {
+    const options = {
+      include: [
+        {
+          model: VideoModel.unscoped(),
+          required: true
+        }
+      ]
+    }
+
+    return VideoFileModel.findById(id, options)
+  }
+
+  static async getStats () {
+    let totalLocalVideoFilesSize = await VideoFileModel.sum('size', {
+      include: [
+        {
+          attributes: [],
+          model: VideoModel.unscoped(),
+          where: {
+            remote: false
+          }
+        }
+      ]
+    } as any)
+    // Sequelize could return null...
+    if (!totalLocalVideoFilesSize) totalLocalVideoFilesSize = 0
 
-// ------------------------------ METHODS ------------------------------
+    return {
+      totalLocalVideoFilesSize
+    }
+  }
+
+  hasSameUniqueKeysThan (other: VideoFileModel) {
+    return this.fps === other.fps &&
+      this.resolution === other.resolution &&
+      this.videoId === other.videoId
+  }
+}