Relax videos list thumbnail api join
[oweals/peertube.git] / server / models / video / video-file.ts
1 import {
2   AllowNull,
3   BelongsTo,
4   Column,
5   CreatedAt,
6   DataType,
7   Default,
8   ForeignKey,
9   HasMany,
10   Is,
11   Model,
12   Table,
13   UpdatedAt
14 } from 'sequelize-typescript'
15 import {
16   isVideoFileExtnameValid,
17   isVideoFileInfoHashValid,
18   isVideoFileResolutionValid,
19   isVideoFileSizeValid,
20   isVideoFPSResolutionValid
21 } from '../../helpers/custom-validators/videos'
22 import { parseAggregateResult, throwIfNotValid } from '../utils'
23 import { VideoModel } from './video'
24 import { VideoRedundancyModel } from '../redundancy/video-redundancy'
25 import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
26 import { FindOptions, QueryTypes, Transaction } from 'sequelize'
27
28 @Table({
29   tableName: 'videoFile',
30   indexes: [
31     {
32       fields: [ 'videoId' ]
33     },
34     {
35       fields: [ 'infoHash' ]
36     },
37     {
38       fields: [ 'videoId', 'resolution', 'fps' ],
39       unique: true
40     }
41   ]
42 })
43 export class VideoFileModel extends Model<VideoFileModel> {
44   @CreatedAt
45   createdAt: Date
46
47   @UpdatedAt
48   updatedAt: Date
49
50   @AllowNull(false)
51   @Is('VideoFileResolution', value => throwIfNotValid(value, isVideoFileResolutionValid, 'resolution'))
52   @Column
53   resolution: number
54
55   @AllowNull(false)
56   @Is('VideoFileSize', value => throwIfNotValid(value, isVideoFileSizeValid, 'size'))
57   @Column(DataType.BIGINT)
58   size: number
59
60   @AllowNull(false)
61   @Is('VideoFileExtname', value => throwIfNotValid(value, isVideoFileExtnameValid, 'extname'))
62   @Column
63   extname: string
64
65   @AllowNull(false)
66   @Is('VideoFileInfohash', value => throwIfNotValid(value, isVideoFileInfoHashValid, 'info hash'))
67   @Column
68   infoHash: string
69
70   @AllowNull(false)
71   @Default(-1)
72   @Is('VideoFileFPS', value => throwIfNotValid(value, isVideoFPSResolutionValid, 'fps'))
73   @Column
74   fps: number
75
76   @ForeignKey(() => VideoModel)
77   @Column
78   videoId: number
79
80   @BelongsTo(() => VideoModel, {
81     foreignKey: {
82       allowNull: false
83     },
84     onDelete: 'CASCADE'
85   })
86   Video: VideoModel
87
88   @HasMany(() => VideoRedundancyModel, {
89     foreignKey: {
90       allowNull: true
91     },
92     onDelete: 'CASCADE',
93     hooks: true
94   })
95   RedundancyVideos: VideoRedundancyModel[]
96
97   static doesInfohashExist (infoHash: string) {
98     const query = 'SELECT 1 FROM "videoFile" WHERE "infoHash" = $infoHash LIMIT 1'
99     const options = {
100       type: QueryTypes.SELECT,
101       bind: { infoHash },
102       raw: true
103     }
104
105     return VideoModel.sequelize.query(query, options)
106               .then(results => results.length === 1)
107   }
108
109   static loadWithVideo (id: number) {
110     const options = {
111       include: [
112         {
113           model: VideoModel.unscoped(),
114           required: true
115         }
116       ]
117     }
118
119     return VideoFileModel.findByPk(id, options)
120   }
121
122   static listByStreamingPlaylist (streamingPlaylistId: number, transaction: Transaction) {
123     const query = {
124       include: [
125         {
126           model: VideoModel.unscoped(),
127           required: true,
128           include: [
129             {
130               model: VideoStreamingPlaylistModel.unscoped(),
131               required: true,
132               where: {
133                 id: streamingPlaylistId
134               }
135             }
136           ]
137         }
138       ],
139       transaction
140     }
141
142     return VideoFileModel.findAll(query)
143   }
144
145   static getStats () {
146     const query: FindOptions = {
147       include: [
148         {
149           attributes: [],
150           model: VideoModel.unscoped(),
151           where: {
152             remote: false
153           }
154         }
155       ]
156     }
157
158     return VideoFileModel.aggregate('size', 'SUM', query)
159       .then(result => ({
160         totalLocalVideoFilesSize: parseAggregateResult(result)
161       }))
162   }
163
164   hasSameUniqueKeysThan (other: VideoFileModel) {
165     return this.fps === other.fps &&
166       this.resolution === other.resolution &&
167       this.videoId === other.videoId
168   }
169 }