aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video-playlist.ts
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-04-17 10:07:00 +0200
committerChocobozzz <me@florianbigard.com>2019-04-24 16:25:52 +0200
commite8bafea35bc930cb8ac5b2d521a188642a1adffe (patch)
tree7537f957ed7307b464e3c90b71b813d992acaade /server/models/video/video-playlist.ts
parent94565d52bb2883e09f16d1363170ac9c0dccb7a1 (diff)
downloadPeerTube-e8bafea35bc930cb8ac5b2d521a188642a1adffe.tar.gz
PeerTube-e8bafea35bc930cb8ac5b2d521a188642a1adffe.tar.zst
PeerTube-e8bafea35bc930cb8ac5b2d521a188642a1adffe.zip
Create a dedicated table to track video thumbnails
Diffstat (limited to 'server/models/video/video-playlist.ts')
-rw-r--r--server/models/video/video-playlist.ts85
1 files changed, 56 insertions, 29 deletions
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index 0725b752a..073609c24 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -1,6 +1,5 @@
1import { 1import {
2 AllowNull, 2 AllowNull,
3 BeforeDestroy,
4 BelongsTo, 3 BelongsTo,
5 Column, 4 Column,
6 CreatedAt, 5 CreatedAt,
@@ -8,6 +7,7 @@ import {
8 Default, 7 Default,
9 ForeignKey, 8 ForeignKey,
10 HasMany, 9 HasMany,
10 HasOne,
11 Is, 11 Is,
12 IsUUID, 12 IsUUID,
13 Model, 13 Model,
@@ -40,16 +40,16 @@ import { join } from 'path'
40import { VideoPlaylistElementModel } from './video-playlist-element' 40import { VideoPlaylistElementModel } from './video-playlist-element'
41import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' 41import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object'
42import { activityPubCollectionPagination } from '../../helpers/activitypub' 42import { activityPubCollectionPagination } from '../../helpers/activitypub'
43import { remove } from 'fs-extra'
44import { logger } from '../../helpers/logger'
45import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model' 43import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model'
46import { CONFIG } from '../../initializers/config' 44import { ThumbnailModel } from './thumbnail'
45import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
47 46
48enum ScopeNames { 47enum ScopeNames {
49 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', 48 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
50 WITH_VIDEOS_LENGTH = 'WITH_VIDEOS_LENGTH', 49 WITH_VIDEOS_LENGTH = 'WITH_VIDEOS_LENGTH',
51 WITH_ACCOUNT_AND_CHANNEL_SUMMARY = 'WITH_ACCOUNT_AND_CHANNEL_SUMMARY', 50 WITH_ACCOUNT_AND_CHANNEL_SUMMARY = 'WITH_ACCOUNT_AND_CHANNEL_SUMMARY',
52 WITH_ACCOUNT = 'WITH_ACCOUNT', 51 WITH_ACCOUNT = 'WITH_ACCOUNT',
52 WITH_THUMBNAIL = 'WITH_THUMBNAIL',
53 WITH_ACCOUNT_AND_CHANNEL = 'WITH_ACCOUNT_AND_CHANNEL' 53 WITH_ACCOUNT_AND_CHANNEL = 'WITH_ACCOUNT_AND_CHANNEL'
54} 54}
55 55
@@ -62,6 +62,14 @@ type AvailableForListOptions = {
62} 62}
63 63
64@Scopes({ 64@Scopes({
65 [ ScopeNames.WITH_THUMBNAIL ]: {
66 include: [
67 {
68 model: () => ThumbnailModel,
69 required: false
70 }
71 ]
72 },
65 [ ScopeNames.WITH_VIDEOS_LENGTH ]: { 73 [ ScopeNames.WITH_VIDEOS_LENGTH ]: {
66 attributes: { 74 attributes: {
67 include: [ 75 include: [
@@ -256,12 +264,15 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
256 }) 264 })
257 VideoPlaylistElements: VideoPlaylistElementModel[] 265 VideoPlaylistElements: VideoPlaylistElementModel[]
258 266
259 @BeforeDestroy 267 @HasOne(() => ThumbnailModel, {
260 static async removeFiles (instance: VideoPlaylistModel) { 268 foreignKey: {
261 logger.info('Removing files of video playlist %s.', instance.url) 269 name: 'videoPlaylistId',
262 270 allowNull: true
263 return instance.removeThumbnail() 271 },
264 } 272 onDelete: 'CASCADE',
273 hooks: true
274 })
275 Thumbnail: ThumbnailModel
265 276
266 static listForApi (options: { 277 static listForApi (options: {
267 followerActorId: number 278 followerActorId: number
@@ -292,7 +303,8 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
292 } as AvailableForListOptions 303 } as AvailableForListOptions
293 ] 304 ]
294 } as any, // FIXME: typings 305 } as any, // FIXME: typings
295 ScopeNames.WITH_VIDEOS_LENGTH 306 ScopeNames.WITH_VIDEOS_LENGTH,
307 ScopeNames.WITH_THUMBNAIL
296 ] 308 ]
297 309
298 return VideoPlaylistModel 310 return VideoPlaylistModel
@@ -365,7 +377,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
365 } 377 }
366 378
367 return VideoPlaylistModel 379 return VideoPlaylistModel
368 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY, ScopeNames.WITH_VIDEOS_LENGTH ]) 380 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY, ScopeNames.WITH_VIDEOS_LENGTH, ScopeNames.WITH_THUMBNAIL ])
369 .findOne(query) 381 .findOne(query)
370 } 382 }
371 383
@@ -378,7 +390,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
378 } 390 }
379 391
380 return VideoPlaylistModel 392 return VideoPlaylistModel
381 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL, ScopeNames.WITH_VIDEOS_LENGTH ]) 393 .scope([ ScopeNames.WITH_ACCOUNT_AND_CHANNEL, ScopeNames.WITH_VIDEOS_LENGTH, ScopeNames.WITH_THUMBNAIL ])
382 .findOne(query) 394 .findOne(query)
383 } 395 }
384 396
@@ -389,7 +401,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
389 } 401 }
390 } 402 }
391 403
392 return VideoPlaylistModel.scope(ScopeNames.WITH_ACCOUNT).findOne(query) 404 return VideoPlaylistModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_THUMBNAIL ]).findOne(query)
393 } 405 }
394 406
395 static getPrivacyLabel (privacy: VideoPlaylistPrivacy) { 407 static getPrivacyLabel (privacy: VideoPlaylistPrivacy) {
@@ -411,24 +423,34 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
411 return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query) 423 return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query)
412 } 424 }
413 425
414 getThumbnailName () { 426 setThumbnail (thumbnail: ThumbnailModel) {
427 this.Thumbnail = thumbnail
428 }
429
430 getThumbnail () {
431 return this.Thumbnail
432 }
433
434 hasThumbnail () {
435 return !!this.Thumbnail
436 }
437
438 generateThumbnailName () {
415 const extension = '.jpg' 439 const extension = '.jpg'
416 440
417 return 'playlist-' + this.uuid + extension 441 return 'playlist-' + this.uuid + extension
418 } 442 }
419 443
420 getThumbnailUrl () { 444 getThumbnailUrl () {
421 return WEBSERVER.URL + STATIC_PATHS.THUMBNAILS + this.getThumbnailName() 445 if (!this.hasThumbnail()) return null
446
447 return WEBSERVER.URL + STATIC_PATHS.THUMBNAILS + this.getThumbnail().filename
422 } 448 }
423 449
424 getThumbnailStaticPath () { 450 getThumbnailStaticPath () {
425 return join(STATIC_PATHS.THUMBNAILS, this.getThumbnailName()) 451 if (!this.hasThumbnail()) return null
426 }
427 452
428 removeThumbnail () { 453 return join(STATIC_PATHS.THUMBNAILS, this.getThumbnail().filename)
429 const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName())
430 return remove(thumbnailPath)
431 .catch(err => logger.warn('Cannot delete thumbnail %s.', thumbnailPath, { err }))
432 } 454 }
433 455
434 setAsRefreshed () { 456 setAsRefreshed () {
@@ -482,6 +504,17 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
482 return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) 504 return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t)
483 } 505 }
484 506
507 let icon: ActivityIconObject
508 if (this.hasThumbnail()) {
509 icon = {
510 type: 'Image' as 'Image',
511 url: this.getThumbnailUrl(),
512 mediaType: 'image/jpeg' as 'image/jpeg',
513 width: THUMBNAILS_SIZE.width,
514 height: THUMBNAILS_SIZE.height
515 }
516 }
517
485 return activityPubCollectionPagination(this.url, handler, page) 518 return activityPubCollectionPagination(this.url, handler, page)
486 .then(o => { 519 .then(o => {
487 return Object.assign(o, { 520 return Object.assign(o, {
@@ -492,13 +525,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
492 published: this.createdAt.toISOString(), 525 published: this.createdAt.toISOString(),
493 updated: this.updatedAt.toISOString(), 526 updated: this.updatedAt.toISOString(),
494 attributedTo: this.VideoChannel ? [ this.VideoChannel.Actor.url ] : [], 527 attributedTo: this.VideoChannel ? [ this.VideoChannel.Actor.url ] : [],
495 icon: { 528 icon
496 type: 'Image' as 'Image',
497 url: this.getThumbnailUrl(),
498 mediaType: 'image/jpeg' as 'image/jpeg',
499 width: THUMBNAILS_SIZE.width,
500 height: THUMBNAILS_SIZE.height
501 }
502 }) 529 })
503 }) 530 })
504 } 531 }