BEARKING CHANGE: Update videos API response
authorChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 10:04:40 +0000 (11:04 +0100)
committerChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 10:04:40 +0000 (11:04 +0100)
before beta

12 files changed:
CHANGELOG.md
client/src/app/shared/video/video-details.model.ts
client/src/app/shared/video/video-edit.model.ts
client/src/app/shared/video/video.model.ts
client/src/app/videos/+video-edit/video-update.component.ts
client/src/app/videos/+video-watch/modal/video-download.component.html
client/src/app/videos/+video-watch/modal/video-download.component.ts
client/src/app/videos/+video-watch/video-watch.component.html
client/src/assets/player/peertube-videojs-plugin.ts
server/tests/real-world/real-world.ts
server/tests/utils/videos/videos.ts
shared/models/videos/video.model.ts

index 4e3248835929bb27138a3c632349ab2296d2ac60..04b8b7c3128d45251989f9c37b31877e8cf6352f 100644 (file)
@@ -1,5 +1,32 @@
 # Changelog
 
+## v1.0.0-alpha.9
+
+### BREAKING CHANGES
+
+* Update videos list/search/get API response:
+   * Removed `resolution` field
+   * Removed `resolutionLabel` field
+   * Removed `category` field
+   * Removed `categoryLabel` field
+   * Removed `licence` field
+   * Removed `licenceLabel` field
+   * Removed `language` field
+   * Removed `languageLabel` field
+   * Removed `privacy` field
+   * Removed `privacyLabel` field
+   * Added `resolution.id` field
+   * Added `resolution.label` field
+   * Added `category.id` field
+   * Added `category.label` field
+   * Added `licence.id` field
+   * Added `licence.label` field
+   * Added `language.id` field
+   * Added `language.label` field
+   * Added `privacy.id` field
+   * Added `privacy.label` field
+
+
 ## v1.0.0-alpha.8
 
 ### Features
index 1882a8165567b88ba583357814fc612f6453ca79..9fc326beb35af62f613070e05c9c8222a4d31303 100644 (file)
@@ -1,57 +1,33 @@
 import {
-  UserRight, VideoChannel, VideoDetails as VideoDetailsServerModel, VideoFile, VideoPrivacy,
+  UserRight,
+  VideoChannel,
+  VideoDetails as VideoDetailsServerModel,
+  VideoFile,
+  VideoPrivacy,
   VideoResolution
 } from '../../../../../shared'
 import { Account } from '../../../../../shared/models/actors'
+import { VideoConstant } from '../../../../../shared/models/videos/video.model'
 import { AuthUser } from '../../core'
 import { Video } from '../../shared/video/video.model'
 
 export class VideoDetails extends Video implements VideoDetailsServerModel {
-  accountName: string
-  by: string
-  createdAt: Date
-  updatedAt: Date
-  categoryLabel: string
-  category: number
-  licenceLabel: string
-  licence: number
-  languageLabel: string
-  language: number
-  description: string
+  privacy: VideoConstant<VideoPrivacy>
+  descriptionPath: string
   support: string
-  duration: number
-  durationLabel: string
-  id: number
-  uuid: string
-  isLocal: boolean
-  name: string
-  serverHost: string
+  channel: VideoChannel
   tags: string[]
-  thumbnailPath: string
-  thumbnailUrl: string
-  previewPath: string
-  previewUrl: string
-  embedPath: string
-  embedUrl: string
-  views: number
-  likes: number
-  dislikes: number
-  nsfw: boolean
-  descriptionPath: string
   files: VideoFile[]
-  channel: VideoChannel
-  privacy: VideoPrivacy
-  privacyLabel: string
   account: Account
+  commentsEnabled: boolean
+
   likesPercent: number
   dislikesPercent: number
-  commentsEnabled: boolean
 
   constructor (hash: VideoDetailsServerModel) {
     super(hash)
 
     this.privacy = hash.privacy
-    this.privacyLabel = hash.privacyLabel
     this.descriptionPath = hash.descriptionPath
     this.files = hash.files
     this.channel = hash.channel
@@ -72,14 +48,14 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
 
     // If the download speed is too bad, return the lowest resolution we have
     if (betterResolutionFile === undefined) {
-      betterResolutionFile = this.files.find(f => f.resolution === VideoResolution.H_240P)
+      betterResolutionFile = this.files.find(f => f.resolution.id === VideoResolution.H_240P)
     }
 
     return betterResolutionFile.magnetUri
   }
 
   isRemovableBy (user: AuthUser) {
-    return user && this.isLocal === true && (this.accountName === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
+    return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.REMOVE_ANY_VIDEO))
   }
 
   isBlackistableBy (user: AuthUser) {
@@ -87,7 +63,7 @@ export class VideoDetails extends Video implements VideoDetailsServerModel {
   }
 
   isUpdatableBy (user: AuthUser) {
-    return user && this.isLocal === true && (this.accountName === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO))
+    return user && this.isLocal === true && (this.account.name === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO))
   }
 
   buildLikeAndDislikePercents () {
index a8bbb63eb2c48b37422d26e4249765c84cedc977..c1a70d1b36ada555342c08df91957a370425410f 100644 (file)
@@ -24,16 +24,16 @@ export class VideoEdit {
     if (videoDetails) {
       this.id = videoDetails.id
       this.uuid = videoDetails.uuid
-      this.category = videoDetails.category
-      this.licence = videoDetails.licence
-      this.language = videoDetails.language
+      this.category = videoDetails.category.id
+      this.licence = videoDetails.licence.id
+      this.language = videoDetails.language.id
       this.description = videoDetails.description
       this.name = videoDetails.name
       this.tags = videoDetails.tags
       this.nsfw = videoDetails.nsfw
       this.commentsEnabled = videoDetails.commentsEnabled
       this.channel = videoDetails.channel.id
-      this.privacy = videoDetails.privacy
+      this.privacy = videoDetails.privacy.id
       this.support = videoDetails.support
       this.thumbnailUrl = videoDetails.thumbnailUrl
       this.previewUrl = videoDetails.previewUrl
index 50ca9eb9934d11e09252ab14d979dfbbe1bd1fc5..7b68933a1c88a51ae4f2d84122c9a28d8366bbe9 100644 (file)
@@ -2,18 +2,16 @@ import { Account } from '@app/shared/account/account.model'
 import { User } from '../'
 import { Video as VideoServerModel } from '../../../../../shared'
 import { Avatar } from '../../../../../shared/models/avatars/avatar.model'
+import { VideoConstant } from '../../../../../shared/models/videos/video.model'
 import { getAbsoluteAPIUrl } from '../misc/utils'
 
 export class Video implements VideoServerModel {
   by: string
   createdAt: Date
   updatedAt: Date
-  categoryLabel: string
-  category: number
-  licenceLabel: string
-  licence: number
-  languageLabel: string
-  language: number
+  category: VideoConstant<number>
+  licence: VideoConstant<number>
+  language: VideoConstant<number>
   description: string
   duration: number
   durationLabel: string
@@ -58,11 +56,8 @@ export class Video implements VideoServerModel {
     const absoluteAPIUrl = getAbsoluteAPIUrl()
 
     this.createdAt = new Date(hash.createdAt.toString())
-    this.categoryLabel = hash.categoryLabel
     this.category = hash.category
-    this.licenceLabel = hash.licenceLabel
     this.licence = hash.licence
-    this.languageLabel = hash.languageLabel
     this.language = hash.language
     this.description = hash.description
     this.duration = hash.duration
index 2fc09278c6bf5f17a64eb70535bcbef2b738919d..6cd204f7252e9bb387963e939c5ffe9d10f8ca13 100644 (file)
@@ -72,7 +72,7 @@ export class VideoUpdateComponent extends FormReactive implements OnInit {
           ]
 
           // We cannot set private a video that was not private
-          if (video.privacy !== VideoPrivacy.PRIVATE) {
+          if (video.privacy.id !== VideoPrivacy.PRIVATE) {
             const newVideoPrivacies = []
             for (const p of this.videoPrivacies) {
               if (p.id !== VideoPrivacy.PRIVATE) newVideoPrivacies.push(p)
index f8f17a47131e0b1b97b32f4a17851d595b2e641f..617892b111ba97ed25238264d9c2f3c8231e5f83 100644 (file)
@@ -9,8 +9,8 @@
 
       <div class="modal-body">
         <div class="peertube-select-container">
-          <select [(ngModel)]="resolution">
-            <option *ngFor="let file of video.files" [value]="file.resolution">{{ file.resolutionLabel }}</option>
+          <select [(ngModel)]="resolutionId">
+            <option *ngFor="let file of video.files" [value]="file.resolution.id">{{ file.resolution.label }}</option>
           </select>
         </div>
 
index 3b409e2e6656c700f6eeab5024e3f1b514e21070..b06a7eef1741f88c629a1fb9ee3605bb15d6e45e 100644 (file)
@@ -13,14 +13,14 @@ export class VideoDownloadComponent implements OnInit {
   @ViewChild('modal') modal: ModalDirective
 
   downloadType: 'direct' | 'torrent' = 'torrent'
-  resolution: number | string = -1
+  resolutionId: number | string = -1
 
   constructor () {
     // empty
   }
 
   ngOnInit () {
-    this.resolution = this.video.files[0].resolution
+    this.resolutionId = this.video.files[0].resolution.id
   }
 
   show () {
@@ -33,11 +33,11 @@ export class VideoDownloadComponent implements OnInit {
 
   download () {
     // HTML select send us a string, so convert it to a number
-    this.resolution = parseInt(this.resolution.toString(), 10)
+    this.resolutionId = parseInt(this.resolutionId.toString(), 10)
 
-    const file = this.video.files.find(f => f.resolution === this.resolution)
+    const file = this.video.files.find(f => f.resolution.id === this.resolutionId)
     if (!file) {
-      console.error('Could not find file with resolution %d.', this.resolution)
+      console.error('Could not find file with resolution %d.', this.resolutionId)
       return
     }
 
index 82f148e9b19222d6ef185cb7877669846907b636..6a7da06140e3669167dd64efbeaba2642c914974 100644 (file)
             Privacy
           </span>
           <span class="video-attribute-value">
-            {{ video.privacyLabel }}
+            {{ video.privacy.label }}
           </span>
         </div>
 
             Category
           </span>
           <span class="video-attribute-value">
-            {{ video.categoryLabel }}
+            {{ video.category.label }}
           </span>
         </div>
 
             Licence
           </span>
           <span class="video-attribute-value">
-            {{ video.licenceLabel }}
+            {{ video.licence.label }}
           </span>
         </div>
 
             Language
           </span>
           <span class="video-attribute-value">
-            {{ video.languageLabel }}
+            {{ video.language.label }}
           </span>
         </div>
 
index a96f6d1a1062dad341be2349cf92c310d0e5c1d3..c99363fb52e65a90b6dfb99f9f0804cf6b76f335 100644 (file)
@@ -2,6 +2,7 @@
 
 import * as videojs from 'video.js'
 import * as WebTorrent from 'webtorrent'
+import { VideoConstant, VideoResolution } from '../../../../shared/models/videos'
 import { VideoFile } from '../../../../shared/models/videos/video.model'
 import { renderVideo } from './video-renderer'
 
@@ -52,8 +53,8 @@ class ResolutionMenuItem extends MenuItem {
     options.selectable = true
     super(player, options)
 
-    const currentResolution = this.player_.peertube().getCurrentResolution()
-    this.selected(this.options_.id === currentResolution)
+    const currentResolutionId = this.player_.peertube().getCurrentResolutionId()
+    this.selected(this.options_.id === currentResolutionId)
   }
 
   handleClick (event) {
@@ -89,10 +90,10 @@ class ResolutionMenuButton extends MenuButton {
       menuItems.push(new ResolutionMenuItem(
         this.player_,
         {
-          id: videoFile.resolution,
-          label: videoFile.resolutionLabel,
+          id: videoFile.resolution.id,
+          label: videoFile.resolution.label,
           src: videoFile.magnetUri,
-          selected: videoFile.resolution === this.currentSelection
+          selected: videoFile.resolution.id === this.currentSelectionId
         })
       )
     }
@@ -269,12 +270,12 @@ class PeerTubePlugin extends Plugin {
     this.flushVideoFile(this.currentVideoFile, false)
   }
 
-  getCurrentResolution () {
-    return this.currentVideoFile ? this.currentVideoFile.resolution : -1
+  getCurrentResolutionId () {
+    return this.currentVideoFile ? this.currentVideoFile.resolution.id : -1
   }
 
   getCurrentResolutionLabel () {
-    return this.currentVideoFile ? this.currentVideoFile.resolutionLabel : ''
+    return this.currentVideoFile ? this.currentVideoFile.resolution.label : ''
   }
 
   updateVideoFile (videoFile?: VideoFile, done?: () => void) {
@@ -339,7 +340,7 @@ class PeerTubePlugin extends Plugin {
     this.trigger('videoFileUpdate')
   }
 
-  updateResolution (resolution) {
+  updateResolution (resolutionId: number) {
     // Remember player state
     const currentTime = this.player.currentTime()
     const isPaused = this.player.paused()
@@ -352,7 +353,7 @@ class PeerTubePlugin extends Plugin {
       this.player.bigPlayButton.hide()
     }
 
-    const newVideoFile = this.videoFiles.find(f => f.resolution === resolution)
+    const newVideoFile = this.videoFiles.find(f => f.resolution.id === resolutionId)
     this.updateVideoFile(newVideoFile, () => {
       this.player.currentTime(currentTime)
       this.player.handleTechSeeked_()
index f10ca856de7f5a85ea33ce70d56eb9f41f715672..ae02ef64daa424f40b4b9d00676c1ba9adbf070a 100644 (file)
@@ -327,7 +327,7 @@ function areDifferences (videos1: Video[], videos2: Video[]) {
             return `Video ${video1.uuid} has missing video file ${videoFile1.magnetUri}.`
           }
 
-          if (videoFile1.size !== videoFile2.size || videoFile1.resolutionLabel !== videoFile2.resolutionLabel) {
+          if (videoFile1.size !== videoFile2.size || videoFile1.resolution.label !== videoFile2.resolution.label) {
             return `Video ${video1.uuid} has different video file ${videoFile1.magnetUri}.`
           }
         })
index 89db16fecd6ef98ebc90417687a69ba57a294e2d..3c63bedb219665760126a5a995b5840fbe456d6b 100644 (file)
@@ -407,12 +407,12 @@ async function completeVideoCheck (
   if (!attributes.dislikes) attributes.dislikes = 0
 
   expect(video.name).to.equal(attributes.name)
-  expect(video.category).to.equal(attributes.category)
-  expect(video.categoryLabel).to.equal(VIDEO_CATEGORIES[attributes.category] || 'Misc')
-  expect(video.licence).to.equal(attributes.licence)
-  expect(video.licenceLabel).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown')
-  expect(video.language).to.equal(attributes.language)
-  expect(video.languageLabel).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown')
+  expect(video.category.id).to.equal(attributes.category)
+  expect(video.category.label).to.equal(VIDEO_CATEGORIES[attributes.category] || 'Misc')
+  expect(video.licence.id).to.equal(attributes.licence)
+  expect(video.licence.label).to.equal(VIDEO_LICENCES[attributes.licence] || 'Unknown')
+  expect(video.language.id).to.equal(attributes.language)
+  expect(video.language.label).to.equal(VIDEO_LANGUAGES[attributes.language] || 'Unknown')
   expect(video.nsfw).to.equal(attributes.nsfw)
   expect(video.description).to.equal(attributes.description)
   expect(video.account.host).to.equal(attributes.account.host)
@@ -429,8 +429,8 @@ async function completeVideoCheck (
 
   expect(videoDetails.files).to.have.lengthOf(attributes.files.length)
   expect(videoDetails.tags).to.deep.equal(attributes.tags)
-  expect(videoDetails.privacy).to.deep.equal(attributes.privacy)
-  expect(videoDetails.privacyLabel).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
+  expect(videoDetails.privacy.id).to.deep.equal(attributes.privacy)
+  expect(videoDetails.privacy.label).to.deep.equal(VIDEO_PRIVACIES[attributes.privacy])
   expect(videoDetails.account.name).to.equal(attributes.account.name)
   expect(videoDetails.account.host).to.equal(attributes.account.host)
   expect(videoDetails.commentsEnabled).to.equal(attributes.commentsEnabled)
@@ -453,8 +453,8 @@ async function completeVideoCheck (
     expect(file.magnetUri).to.have.lengthOf.above(2)
     expect(file.torrentUrl).to.equal(`http://${attributes.account.host}/static/torrents/${videoDetails.uuid}-${file.resolution}.torrent`)
     expect(file.fileUrl).to.equal(`http://${attributes.account.host}/static/webseed/${videoDetails.uuid}-${file.resolution}${extension}`)
-    expect(file.resolution).to.equal(attributeFile.resolution)
-    expect(file.resolutionLabel).to.equal(attributeFile.resolution + 'p')
+    expect(file.resolution.id).to.equal(attributeFile.resolution)
+    expect(file.resolution.label).to.equal(attributeFile.resolution + 'p')
 
     const minSize = attributeFile.size - ((10 * attributeFile.size) / 100)
     const maxSize = attributeFile.size + ((10 * attributeFile.size) / 100)
index 6a096195f1865a3ec07f0818494afdad8dfbdae1..ebd2813ca5f4ac554a9aba511817ca01242b84c2 100644 (file)
@@ -1,3 +1,4 @@
+import { VideoResolution } from '../../index'
 import { Account } from '../actors'
 import { Avatar } from '../avatars/avatar.model'
 import { VideoChannel } from './video-channel.model'
@@ -10,7 +11,7 @@ export interface VideoConstant <T> {
 
 export interface VideoFile {
   magnetUri: string
-  resolution: VideoConstant<number>
+  resolution: VideoConstant<VideoResolution>
   size: number // Bytes
   torrentUrl: string
   fileUrl: string