]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/models/video/video-playlist.ts
Don't use the max quality file when transcoding to a new resolution
[github/Chocobozzz/PeerTube.git] / server / models / video / video-playlist.ts
index 073609c24baaacc7347a6ace6c2fe0aeb54c5364..278d80ac051d2144cd34be068256b3425f3d2e93 100644 (file)
@@ -15,7 +15,6 @@ import {
   Table,
   UpdatedAt
 } from 'sequelize-typescript'
-import * as Sequelize from 'sequelize'
 import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
 import { buildServerIdsFollowedBy, buildWhereIdOrUUID, getSort, isOutdated, throwIfNotValid } from '../utils'
 import {
@@ -34,7 +33,7 @@ import {
   WEBSERVER
 } from '../../initializers/constants'
 import { VideoPlaylist } from '../../../shared/models/videos/playlist/video-playlist.model'
-import { AccountModel, ScopeNames as AccountScopeNames } from '../account/account'
+import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account'
 import { ScopeNames as VideoChannelScopeNames, VideoChannelModel } from './video-channel'
 import { join } from 'path'
 import { VideoPlaylistElementModel } from './video-playlist-element'
@@ -43,6 +42,16 @@ import { activityPubCollectionPagination } from '../../helpers/activitypub'
 import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model'
 import { ThumbnailModel } from './thumbnail'
 import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
+import { FindOptions, literal, Op, ScopeOptions, Transaction, WhereOptions } from 'sequelize'
+import * as Bluebird from 'bluebird'
+import {
+  MVideoPlaylistAccountThumbnail, MVideoPlaylistAP,
+  MVideoPlaylistFormattable,
+  MVideoPlaylistFull,
+  MVideoPlaylistFullSummary,
+  MVideoPlaylistIdWithElements
+} from '../../typings/models/video/video-playlist'
+import { MThumbnail } from '../../typings/models/video/thumbnail'
 
 enum ScopeNames {
   AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
@@ -61,11 +70,11 @@ type AvailableForListOptions = {
   privateAndUnlisted?: boolean
 }
 
-@Scopes({
+@Scopes(() => ({
   [ ScopeNames.WITH_THUMBNAIL ]: {
     include: [
       {
-        model: () => ThumbnailModel,
+        model: ThumbnailModel,
         required: false
       }
     ]
@@ -74,16 +83,16 @@ type AvailableForListOptions = {
     attributes: {
       include: [
         [
-          Sequelize.literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'),
+          literal('(SELECT COUNT("id") FROM "videoPlaylistElement" WHERE "videoPlaylistId" = "VideoPlaylistModel"."id")'),
           'videosLength'
         ]
       ]
     }
-  },
+  } as FindOptions,
   [ ScopeNames.WITH_ACCOUNT ]: {
     include: [
       {
-        model: () => AccountModel,
+        model: AccountModel,
         required: true
       }
     ]
@@ -91,11 +100,11 @@ type AvailableForListOptions = {
   [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL_SUMMARY ]: {
     include: [
       {
-        model: () => AccountModel.scope(AccountScopeNames.SUMMARY),
+        model: AccountModel.scope(AccountScopeNames.SUMMARY),
         required: true
       },
       {
-        model: () => VideoChannelModel.scope(VideoChannelScopeNames.SUMMARY),
+        model: VideoChannelModel.scope(VideoChannelScopeNames.SUMMARY),
         required: false
       }
     ]
@@ -103,11 +112,11 @@ type AvailableForListOptions = {
   [ ScopeNames.WITH_ACCOUNT_AND_CHANNEL ]: {
     include: [
       {
-        model: () => AccountModel,
+        model: AccountModel,
         required: true
       },
       {
-        model: () => VideoChannelModel,
+        model: VideoChannelModel,
         required: false
       }
     ]
@@ -115,20 +124,20 @@ type AvailableForListOptions = {
   [ ScopeNames.AVAILABLE_FOR_LIST ]: (options: AvailableForListOptions) => {
     // Only list local playlists OR playlists that are on an instance followed by actorId
     const inQueryInstanceFollow = buildServerIdsFollowedBy(options.followerActorId)
-    const actorWhere = {
-      [ Sequelize.Op.or ]: [
+    const whereActor = {
+      [ Op.or ]: [
         {
           serverId: null
         },
         {
           serverId: {
-            [ Sequelize.Op.in ]: Sequelize.literal(inQueryInstanceFollow)
+            [ Op.in ]: literal(inQueryInstanceFollow)
           }
         }
       ]
     }
 
-    const whereAnd: any[] = []
+    const whereAnd: WhereOptions[] = []
 
     if (options.privateAndUnlisted !== true) {
       whereAnd.push({
@@ -155,11 +164,11 @@ type AvailableForListOptions = {
     }
 
     const where = {
-      [Sequelize.Op.and]: whereAnd
+      [Op.and]: whereAnd
     }
 
     const accountScope = {
-      method: [ AccountScopeNames.SUMMARY, actorWhere ]
+      method: [ AccountScopeNames.SUMMARY, { whereActor } as SummaryOptions ]
     }
 
     return {
@@ -174,9 +183,9 @@ type AvailableForListOptions = {
           required: false
         }
       ]
-    }
+    } as FindOptions
   }
-})
+}))
 
 @Table({
   tableName: 'videoPlaylist',
@@ -206,7 +215,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
   name: string
 
   @AllowNull(true)
-  @Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description'))
+  @Is('VideoPlaylistDescription', value => throwIfNotValid(value, isVideoPlaylistDescriptionValid, 'description', true))
   @Column
   description: string
 
@@ -290,7 +299,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
       order: getSort(options.sort)
     }
 
-    const scopes = [
+    const scopes: (string | ScopeOptions)[] = [
       {
         method: [
           ScopeNames.AVAILABLE_FOR_LIST,
@@ -302,7 +311,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
             privateAndUnlisted: options.privateAndUnlisted
           } as AvailableForListOptions
         ]
-      } as any, // FIXME: typings
+      },
       ScopeNames.WITH_VIDEOS_LENGTH,
       ScopeNames.WITH_THUMBNAIL
     ]
@@ -332,7 +341,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
                              })
   }
 
-  static listPlaylistIdsOf (accountId: number, videoIds: number[]) {
+  static listPlaylistIdsOf (accountId: number, videoIds: number[]): Bluebird<MVideoPlaylistIdWithElements[]> {
     const query = {
       attributes: [ 'id' ],
       where: {
@@ -340,11 +349,11 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
       },
       include: [
         {
-          attributes: [ 'videoId', 'startTimestamp', 'stopTimestamp' ],
+          attributes: [ 'id', 'videoId', 'startTimestamp', 'stopTimestamp' ],
           model: VideoPlaylistElementModel.unscoped(),
           where: {
             videoId: {
-              [Sequelize.Op.any]: videoIds
+              [Op.in]: videoIds // FIXME: sequelize ANY seems broken
             }
           },
           required: true
@@ -368,7 +377,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
       .then(e => !!e)
   }
 
-  static loadWithAccountAndChannelSummary (id: number | string, transaction: Sequelize.Transaction) {
+  static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFullSummary> {
     const where = buildWhereIdOrUUID(id)
 
     const query = {
@@ -381,7 +390,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
       .findOne(query)
   }
 
-  static loadWithAccountAndChannel (id: number | string, transaction: Sequelize.Transaction) {
+  static loadWithAccountAndChannel (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFull> {
     const where = buildWhereIdOrUUID(id)
 
     const query = {
@@ -394,7 +403,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
       .findOne(query)
   }
 
-  static loadByUrlAndPopulateAccount (url: string) {
+  static loadByUrlAndPopulateAccount (url: string): Bluebird<MVideoPlaylistAccountThumbnail> {
     const query = {
       where: {
         url
@@ -412,7 +421,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
     return VIDEO_PLAYLIST_TYPES[type] || 'Unknown'
   }
 
-  static resetPlaylistsOfChannel (videoChannelId: number, transaction: Sequelize.Transaction) {
+  static resetPlaylistsOfChannel (videoChannelId: number, transaction: Transaction) {
     const query = {
       where: {
         videoChannelId
@@ -423,18 +432,20 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
     return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query)
   }
 
-  setThumbnail (thumbnail: ThumbnailModel) {
-    this.Thumbnail = thumbnail
-  }
+  async setAndSaveThumbnail (thumbnail: MThumbnail, t: Transaction) {
+    thumbnail.videoPlaylistId = this.id
 
-  getThumbnail () {
-    return this.Thumbnail
+    this.Thumbnail = await thumbnail.save({ transaction: t })
   }
 
   hasThumbnail () {
     return !!this.Thumbnail
   }
 
+  hasGeneratedThumbnail () {
+    return this.hasThumbnail() && this.Thumbnail.automaticallyGenerated === true
+  }
+
   generateThumbnailName () {
     const extension = '.jpg'
 
@@ -444,13 +455,13 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
   getThumbnailUrl () {
     if (!this.hasThumbnail()) return null
 
-    return WEBSERVER.URL + STATIC_PATHS.THUMBNAILS + this.getThumbnail().filename
+    return WEBSERVER.URL + STATIC_PATHS.THUMBNAILS + this.Thumbnail.filename
   }
 
   getThumbnailStaticPath () {
     if (!this.hasThumbnail()) return null
 
-    return join(STATIC_PATHS.THUMBNAILS, this.getThumbnail().filename)
+    return join(STATIC_PATHS.THUMBNAILS, this.Thumbnail.filename)
   }
 
   setAsRefreshed () {
@@ -469,7 +480,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
     return isOutdated(this, ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL)
   }
 
-  toFormattedJSON (): VideoPlaylist {
+  toFormattedJSON (this: MVideoPlaylistFormattable): VideoPlaylist {
     return {
       id: this.id,
       uuid: this.uuid,
@@ -489,7 +500,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
         label: VideoPlaylistModel.getTypeLabel(this.type)
       },
 
-      videosLength: this.get('videosLength'),
+      videosLength: this.get('videosLength') as number,
 
       createdAt: this.createdAt,
       updatedAt: this.updatedAt,
@@ -499,7 +510,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
     }
   }
 
-  toActivityPubObject (page: number, t: Sequelize.Transaction): Promise<PlaylistObject> {
+  toActivityPubObject (this: MVideoPlaylistAP, page: number, t: Transaction): Promise<PlaylistObject> {
     const handler = (start: number, count: number) => {
       return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t)
     }