]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/models/video/video-playlist-element.ts
5530e0492d6463db06e95361fdc4788abad66e09
[github/Chocobozzz/PeerTube.git] / server / models / video / video-playlist-element.ts
1 import {
2 AllowNull,
3 BelongsTo,
4 Column,
5 CreatedAt,
6 DataType,
7 Default,
8 ForeignKey,
9 Is,
10 IsInt,
11 Min,
12 Model,
13 Table,
14 UpdatedAt
15 } from 'sequelize-typescript'
16 import { VideoModel } from './video'
17 import { VideoPlaylistModel } from './video-playlist'
18 import * as Sequelize from 'sequelize'
19 import { getSort, throwIfNotValid } from '../utils'
20 import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
21 import { CONSTRAINTS_FIELDS } from '../../initializers'
22 import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object'
23
24 @Table({
25 tableName: 'videoPlaylistElement',
26 indexes: [
27 {
28 fields: [ 'videoPlaylistId' ]
29 },
30 {
31 fields: [ 'videoId' ]
32 },
33 {
34 fields: [ 'videoPlaylistId', 'videoId' ],
35 unique: true
36 },
37 {
38 fields: [ 'videoPlaylistId', 'position' ],
39 unique: true
40 },
41 {
42 fields: [ 'url' ],
43 unique: true
44 }
45 ]
46 })
47 export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> {
48 @CreatedAt
49 createdAt: Date
50
51 @UpdatedAt
52 updatedAt: Date
53
54 @AllowNull(false)
55 @Is('VideoPlaylistUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
56 @Column(DataType.STRING(CONSTRAINTS_FIELDS.VIDEO_PLAYLISTS.URL.max))
57 url: string
58
59 @AllowNull(false)
60 @Default(1)
61 @IsInt
62 @Min(1)
63 @Column
64 position: number
65
66 @AllowNull(true)
67 @IsInt
68 @Min(0)
69 @Column
70 startTimestamp: number
71
72 @AllowNull(true)
73 @IsInt
74 @Min(0)
75 @Column
76 stopTimestamp: number
77
78 @ForeignKey(() => VideoPlaylistModel)
79 @Column
80 videoPlaylistId: number
81
82 @BelongsTo(() => VideoPlaylistModel, {
83 foreignKey: {
84 allowNull: false
85 },
86 onDelete: 'CASCADE'
87 })
88 VideoPlaylist: VideoPlaylistModel
89
90 @ForeignKey(() => VideoModel)
91 @Column
92 videoId: number
93
94 @BelongsTo(() => VideoModel, {
95 foreignKey: {
96 allowNull: false
97 },
98 onDelete: 'CASCADE'
99 })
100 Video: VideoModel
101
102 static deleteAllOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) {
103 const query = {
104 where: {
105 videoPlaylistId
106 },
107 transaction
108 }
109
110 return VideoPlaylistElementModel.destroy(query)
111 }
112
113 static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number) {
114 const query = {
115 where: {
116 videoPlaylistId,
117 videoId
118 }
119 }
120
121 return VideoPlaylistElementModel.findOne(query)
122 }
123
124 static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string) {
125 const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
126 const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId }
127
128 const query = {
129 include: [
130 {
131 attributes: [ 'privacy' ],
132 model: VideoPlaylistModel.unscoped(),
133 where: playlistWhere
134 },
135 {
136 attributes: [ 'url' ],
137 model: VideoModel.unscoped(),
138 where: videoWhere
139 }
140 ]
141 }
142
143 return VideoPlaylistElementModel.findOne(query)
144 }
145
146 static listUrlsOfForAP (videoPlaylistId: number, start: number, count: number) {
147 const query = {
148 attributes: [ 'url' ],
149 offset: start,
150 limit: count,
151 order: getSort('position'),
152 where: {
153 videoPlaylistId
154 }
155 }
156
157 return VideoPlaylistElementModel
158 .findAndCountAll(query)
159 .then(({ rows, count }) => {
160 return { total: count, data: rows.map(e => e.url) }
161 })
162 }
163
164 static getNextPositionOf (videoPlaylistId: number, transaction?: Sequelize.Transaction) {
165 const query = {
166 where: {
167 videoPlaylistId
168 },
169 transaction
170 }
171
172 return VideoPlaylistElementModel.max('position', query)
173 .then(position => position ? position + 1 : 1)
174 }
175
176 static reassignPositionOf (
177 videoPlaylistId: number,
178 firstPosition: number,
179 endPosition: number,
180 newPosition: number,
181 transaction?: Sequelize.Transaction
182 ) {
183 const query = {
184 where: {
185 videoPlaylistId,
186 position: {
187 [Sequelize.Op.gte]: firstPosition,
188 [Sequelize.Op.lte]: endPosition
189 }
190 },
191 transaction,
192 validate: false // We use a literal to update the position
193 }
194
195 return VideoPlaylistElementModel.update({ position: Sequelize.literal(`${newPosition} + "position" - ${firstPosition}`) }, query)
196 }
197
198 static increasePositionOf (
199 videoPlaylistId: number,
200 fromPosition: number,
201 toPosition?: number,
202 by = 1,
203 transaction?: Sequelize.Transaction
204 ) {
205 const query = {
206 where: {
207 videoPlaylistId,
208 position: {
209 [Sequelize.Op.gte]: fromPosition
210 }
211 },
212 transaction
213 }
214
215 return VideoPlaylistElementModel.increment({ position: by }, query)
216 }
217
218 toActivityPubObject (): PlaylistElementObject {
219 const base: PlaylistElementObject = {
220 id: this.url,
221 type: 'PlaylistElement',
222
223 url: this.Video.url,
224 position: this.position
225 }
226
227 if (this.startTimestamp) base.startTimestamp = this.startTimestamp
228 if (this.stopTimestamp) base.stopTimestamp = this.stopTimestamp
229
230 return base
231 }
232 }