# 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
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
// 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) {
}
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 () {
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
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
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
]
// 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)
<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>
@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 () {
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
}
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>
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'
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) {
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
})
)
}
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) {
this.trigger('videoFileUpdate')
}
- updateResolution (resolution) {
+ updateResolution (resolutionId: number) {
// Remember player state
const currentTime = this.player.currentTime()
const isPaused = this.player.paused()
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_()
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}.`
}
})
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)
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)
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)
+import { VideoResolution } from '../../index'
import { Account } from '../actors'
import { Avatar } from '../avatars/avatar.model'
import { VideoChannel } from './video-channel.model'
export interface VideoFile {
magnetUri: string
- resolution: VideoConstant<number>
+ resolution: VideoConstant<VideoResolution>
size: number // Bytes
torrentUrl: string
fileUrl: string