diff --git a/client/src/app/videos/+video-watch/video-watch.component.scss b/client/src/app/videos/+video-watch/video-watch.component.scss
index ae8bdccaf..71770c93b 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.scss
+++ b/client/src/app/videos/+video-watch/video-watch.component.scss
@@ -28,7 +28,7 @@
}
}
-#warning-transcoding {
+.alert {
text-align: center;
}
diff --git a/client/src/app/videos/+video-watch/video-watch.component.ts b/client/src/app/videos/+video-watch/video-watch.component.ts
index a760c03e8..72e96ca93 100644
--- a/client/src/app/videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/videos/+video-watch/video-watch.component.ts
@@ -280,6 +280,10 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
return this.video && this.video.state.id === VideoState.TO_TRANSCODE
}
+ hasVideoScheduledPublication () {
+ return this.video && this.video.scheduledUpdate !== undefined
+ }
+
private updateVideoDescription (description: string) {
this.video.description = description
this.setVideoDescriptionHTML()
diff --git a/client/src/app/videos/video-list/video-local.component.ts b/client/src/app/videos/video-list/video-local.component.ts
index 2fd82a940..dbe1d937d 100644
--- a/client/src/app/videos/video-list/video-local.component.ts
+++ b/client/src/app/videos/video-list/video-local.component.ts
@@ -9,6 +9,7 @@ import { VideoSortField } from '../../shared/video/sort-field.type'
import { VideoService } from '../../shared/video/video.service'
import { VideoFilter } from '../../../../../shared/models/videos/video-query.type'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { ScreenService } from '@app/shared/misc/screen.service'
@Component({
selector: 'my-videos-local',
@@ -28,6 +29,7 @@ export class VideoLocalComponent extends AbstractVideoList implements OnInit, On
protected authService: AuthService,
protected location: Location,
protected i18n: I18n,
+ protected screenService: ScreenService,
private videoService: VideoService
) {
super()
diff --git a/client/src/app/videos/video-list/video-recently-added.component.ts b/client/src/app/videos/video-list/video-recently-added.component.ts
index 8183357f8..004a49168 100644
--- a/client/src/app/videos/video-list/video-recently-added.component.ts
+++ b/client/src/app/videos/video-list/video-recently-added.component.ts
@@ -8,6 +8,7 @@ import { AbstractVideoList } from '../../shared/video/abstract-video-list'
import { VideoSortField } from '../../shared/video/sort-field.type'
import { VideoService } from '../../shared/video/video.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { ScreenService } from '@app/shared/misc/screen.service'
@Component({
selector: 'my-videos-recently-added',
@@ -26,6 +27,7 @@ export class VideoRecentlyAddedComponent extends AbstractVideoList implements On
protected notificationsService: NotificationsService,
protected authService: AuthService,
protected i18n: I18n,
+ protected screenService: ScreenService,
private videoService: VideoService
) {
super()
diff --git a/client/src/app/videos/video-list/video-search.component.ts b/client/src/app/videos/video-list/video-search.component.ts
index b6434f347..33ed3f00e 100644
--- a/client/src/app/videos/video-list/video-search.component.ts
+++ b/client/src/app/videos/video-list/video-search.component.ts
@@ -9,6 +9,7 @@ import { AuthService } from '../../core/auth'
import { AbstractVideoList } from '../../shared/video/abstract-video-list'
import { VideoService } from '../../shared/video/video.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { ScreenService } from '@app/shared/misc/screen.service'
@Component({
selector: 'my-videos-search',
@@ -32,6 +33,7 @@ export class VideoSearchComponent extends AbstractVideoList implements OnInit, O
protected authService: AuthService,
protected location: Location,
protected i18n: I18n,
+ protected screenService: ScreenService,
private videoService: VideoService,
private redirectService: RedirectService
) {
diff --git a/client/src/app/videos/video-list/video-trending.component.ts b/client/src/app/videos/video-list/video-trending.component.ts
index e56b749d1..f2174aa14 100644
--- a/client/src/app/videos/video-list/video-trending.component.ts
+++ b/client/src/app/videos/video-list/video-trending.component.ts
@@ -8,6 +8,7 @@ import { AbstractVideoList } from '../../shared/video/abstract-video-list'
import { VideoSortField } from '../../shared/video/sort-field.type'
import { VideoService } from '../../shared/video/video.service'
import { I18n } from '@ngx-translate/i18n-polyfill'
+import { ScreenService } from '@app/shared/misc/screen.service'
@Component({
selector: 'my-videos-trending',
@@ -25,6 +26,7 @@ export class VideoTrendingComponent extends AbstractVideoList implements OnInit,
protected notificationsService: NotificationsService,
protected authService: AuthService,
protected location: Location,
+ protected screenService: ScreenService,
protected i18n: I18n,
private videoService: VideoService
) {
diff --git a/client/src/sass/application.scss b/client/src/sass/application.scss
index 4006c9128..dae0c52c2 100644
--- a/client/src/sass/application.scss
+++ b/client/src/sass/application.scss
@@ -6,14 +6,14 @@ $icon-font-path: '../../node_modules/bootstrap-sass/assets/fonts/bootstrap/';
@import '_fonts';
-@import '~primeng/resources/themes/bootstrap/theme.css';
-@import '~primeng/resources/primeng.css';
@import '~video.js/dist/video-js.css';
$assets-path: '../assets/';
@import './player/player';
@import './loading-bar';
+@import './primeng-custom';
+
[hidden] {
display: none !important;
}
@@ -142,126 +142,6 @@ label {
to { transform: scale(1) rotate(360deg);}
}
-// ngprime data table customizations
-p-table {
- font-size: 15px !important;
-
- td {
- border: 1px solid #E5E5E5 !important;
- padding-left: 15px !important;
- overflow: hidden !important;
- text-overflow: ellipsis !important;
- white-space: nowrap !important;
- }
-
- tr {
- background-color: #fff !important;
- height: 46px;
- }
-
- .ui-table-tbody {
- tr {
- &:hover {
- background-color: #f0f0f0 !important;
- }
-
- &:not(:hover) {
- .action-cell * {
- display: none !important;
- }
- }
-
- &:first-child td {
- border-top: none !important;
- }
-
- &:last-child td {
- border-bottom: none !important;
- }
- }
-
- .expander {
- cursor: pointer;
- position: relative;
- top: 1px;
- }
- }
-
- th {
- border: none !important;
- border-bottom: 1px solid #f0f0f0 !important;
- text-align: left !important;
- padding: 5px 0 5px 15px !important;
- font-weight: $font-semibold !important;
- color: #000 !important;
-
- &.ui-sortable-column:hover {
- background-color: #f0f0f0 !important;
- border: 1px solid #f0f0f0 !important;
- border-width: 0 1px !important;
-
- &:first-child {
- border-width: 0 1px 0 0 !important;
- }
- }
-
- &.ui-state-highlight {
- background-color: #fff !important;
-
- .fa {
- @extend .glyphicon;
- font-size: 11px;
-
- &.fa-sort-asc {
- @extend .glyphicon-triangle-top;
- }
-
- &.fa-sort-desc {
- @extend .glyphicon-triangle-bottom;
- }
- }
- }
- }
-
- .action-cell {
- width: 250px !important;
- padding: 0 !important;
- text-align: center;
-
- my-edit-button + my-delete-button {
- margin-left: 5px;
- }
- }
-
- p-paginator {
- .ui-paginator-bottom {
- position: relative;
- border: none !important;
- border: 1px solid #f0f0f0 !important;
- height: 40px;
- display: flex;
- justify-content: center;
- align-items: center;
-
- a {
- color: #000 !important;
- font-weight: $font-semibold !important;
- margin-right: 20px !important;
- outline: 0 !important;
- border-radius: 3px !important;
- padding: 5px 2px !important;
-
- &.ui-state-active {
- &, &:hover, &:active, &:focus {
- color: #fff !important;
- background-color: $orange-color !important;
- }
- }
- }
- }
- }
-}
-
// Bootstrap customizations
.dropdown-menu {
border-radius: 3px;
@@ -352,6 +232,8 @@ tabset:not(.bootstrap) {
}
tabset.bootstrap {
+ margin-left: 0;
+
.nav-item .nav-link {
&, & a {
color: #000;
diff --git a/client/src/sass/include/_mixins.scss b/client/src/sass/include/_mixins.scss
index 748c98afa..3904751c2 100644
--- a/client/src/sass/include/_mixins.scss
+++ b/client/src/sass/include/_mixins.scss
@@ -281,6 +281,12 @@
cursor: pointer;
display: inline;
}
+
+ &[disabled] + label,
+ &[disabled] + label + label{
+ opacity: 0.5;
+ cursor: default;
+ }
}
diff --git a/client/src/sass/primeng-custom.scss b/client/src/sass/primeng-custom.scss
new file mode 100644
index 000000000..b28b20e0f
--- /dev/null
+++ b/client/src/sass/primeng-custom.scss
@@ -0,0 +1,174 @@
+@import '_variables';
+@import '_mixins';
+
+@import '~primeng/resources/primeng.css';
+@import '~primeng/resources/themes/bootstrap/theme.css';
+
+@mixin glyphicon-light {
+ font-family: 'Glyphicons Halflings';
+ text-decoration: none !important;
+ color: #000 !important;
+}
+
+// data table customizations
+p-table {
+ font-size: 15px !important;
+
+ td {
+ border: 1px solid #E5E5E5 !important;
+ padding-left: 15px !important;
+ overflow: hidden !important;
+ text-overflow: ellipsis !important;
+ white-space: nowrap !important;
+ }
+
+ tr {
+ background-color: #fff !important;
+ height: 46px;
+ }
+
+ .ui-table-tbody {
+ tr {
+ &:hover {
+ background-color: #f0f0f0 !important;
+ }
+
+ &:not(:hover) {
+ .action-cell * {
+ display: none !important;
+ }
+ }
+
+ &:first-child td {
+ border-top: none !important;
+ }
+
+ &:last-child td {
+ border-bottom: none !important;
+ }
+ }
+
+ .expander {
+ cursor: pointer;
+ position: relative;
+ top: 1px;
+ }
+ }
+
+ th {
+ border: none !important;
+ border-bottom: 1px solid #f0f0f0 !important;
+ text-align: left !important;
+ padding: 5px 0 5px 15px !important;
+ font-weight: $font-semibold !important;
+ color: #000 !important;
+
+ &.ui-sortable-column:hover {
+ background-color: #f0f0f0 !important;
+ border: 1px solid #f0f0f0 !important;
+ border-width: 0 1px !important;
+
+ &:first-child {
+ border-width: 0 1px 0 0 !important;
+ }
+ }
+
+ &.ui-state-highlight {
+ background-color: #fff !important;
+
+ .pi {
+ @extend .glyphicon;
+
+ color: #000;
+ font-size: 11px;
+
+ &.pi-sort-up {
+ @extend .glyphicon-triangle-top;
+ }
+
+ &.pi-sort-down {
+ @extend .glyphicon-triangle-bottom;
+ }
+ }
+ }
+ }
+
+ .action-cell {
+ width: 250px !important;
+ padding: 0 !important;
+ text-align: center;
+
+ my-edit-button + my-delete-button {
+ margin-left: 5px;
+ }
+ }
+
+ p-paginator {
+ .ui-paginator-bottom {
+ position: relative;
+ border: 1px solid #f0f0f0 !important;
+ height: 40px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ .ui-paginator-pages {
+ height: auto !important;
+
+ a {
+ color: #000 !important;
+ font-weight: $font-semibold !important;
+ margin-right: 20px !important;
+ outline: 0 !important;
+ border-radius: 3px !important;
+ padding: 5px 2px !important;
+ height: auto !important;
+
+ &.ui-state-active {
+ &, &:hover, &:active, &:focus {
+ color: #fff !important;
+ background-color: $orange-color !important;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// PrimeNG calendar tweaks
+p-calendar .ui-datepicker {
+ a {
+ @include disable-default-a-behaviour;
+ }
+
+ .ui-datepicker-header {
+
+ .ui-datepicker-year {
+ margin-left: 5px;
+ }
+
+ .ui-datepicker-next {
+ @extend .glyphicon-chevron-right;
+ @include glyphicon-light;
+ }
+
+ .ui-datepicker-prev {
+ @extend .glyphicon-chevron-left;
+ @include glyphicon-light;
+ }
+ }
+
+ .ui-timepicker {
+
+ .pi.pi-chevron-up {
+ @extend .glyphicon-chevron-up;
+ @include glyphicon-light;
+ }
+
+ .pi.pi-chevron-down {
+ @extend .glyphicon-chevron-down;
+ @include glyphicon-light;
+ }
+ }
+}
\ No newline at end of file
diff --git a/client/yarn.lock b/client/yarn.lock
index e2d0da541..b9b13c18c 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -7656,9 +7656,9 @@ pretty-error@^2.0.2:
renderkid "^2.0.1"
utila "~0.4"
-primeng@^5.2.6:
- version "5.2.7"
- resolved "https://registry.yarnpkg.com/primeng/-/primeng-5.2.7.tgz#9dcf461b6a82ea46de85751dc235ea82303e64b1"
+primeng@^6.0.0-rc.1:
+ version "6.0.0-rc.1"
+ resolved "https://registry.yarnpkg.com/primeng/-/primeng-6.0.0-rc.1.tgz#038e5657a5395e08a5c1fd9312b12cac1a44b527"
private@^0.1.6, private@^0.1.8, private@~0.1.5:
version "0.1.8"
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 164378505..53902071c 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -8,8 +8,6 @@ import { VideoPrivacy } from '../../shared/models/videos'
import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils'
import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
import { invert } from 'lodash'
-import { RemoveOldJobsScheduler } from '../lib/schedulers/remove-old-jobs-scheduler'
-import { UpdateVideosScheduler } from '../lib/schedulers/update-videos-scheduler'
// Use a variable to reload the configuration if we need
let config: IConfig = require('config')
@@ -98,8 +96,8 @@ const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days
// 1 hour
let SCHEDULER_INTERVALS_MS = {
badActorFollow: 60000 * 60, // 1 hour
- removeOldJobs: 60000 * 60, // 1 jour
- updateVideos: 60000 * 1, // 1 minute
+ removeOldJobs: 60000 * 60, // 1 hour
+ updateVideos: 60000 // 1 minute
}
// ---------------------------------------------------------------------------
diff --git a/server/lib/schedulers/update-videos-scheduler.ts b/server/lib/schedulers/update-videos-scheduler.ts
index d123c3ceb..a964648fd 100644
--- a/server/lib/schedulers/update-videos-scheduler.ts
+++ b/server/lib/schedulers/update-videos-scheduler.ts
@@ -33,7 +33,9 @@ export class UpdateVideosScheduler extends AbstractScheduler {
}
}
- private updateVideos () {
+ private async updateVideos () {
+ if (!await ScheduleVideoUpdateModel.areVideosToUpdate()) return undefined
+
return sequelizeTypescript.transaction(async t => {
const schedules = await ScheduleVideoUpdateModel.listVideosToUpdate(t)
diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts
index 9fe5a253b..da17b4a68 100644
--- a/server/middlewares/validators/videos.ts
+++ b/server/middlewares/validators/videos.ts
@@ -223,7 +223,7 @@ const videosUpdateValidator = [
if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) {
return res.status(409)
- .json({ error: 'Cannot set "private" a video that was not private anymore.' })
+ .json({ error: 'Cannot set "private" a video that was not private.' })
.end()
}
diff --git a/server/models/video/schedule-video-update.ts b/server/models/video/schedule-video-update.ts
index d4e37beb5..3cf5f6c99 100644
--- a/server/models/video/schedule-video-update.ts
+++ b/server/models/video/schedule-video-update.ts
@@ -25,7 +25,7 @@ export class ScheduleVideoUpdateModel extends Model
{
@AllowNull(true)
@Default(null)
@Column
- privacy: VideoPrivacy
+ privacy: VideoPrivacy.PUBLIC | VideoPrivacy.UNLISTED
@CreatedAt
createdAt: Date
@@ -45,6 +45,21 @@ export class ScheduleVideoUpdateModel extends Model {
})
Video: VideoModel
+ static areVideosToUpdate () {
+ const query = {
+ logging: false,
+ attributes: [ 'id' ],
+ where: {
+ updateAt: {
+ [Sequelize.Op.lte]: new Date()
+ }
+ }
+ }
+
+ return ScheduleVideoUpdateModel.findOne(query)
+ .then(res => !!res)
+ }
+
static listVideosToUpdate (t: Transaction) {
const query = {
where: {
@@ -68,4 +83,10 @@ export class ScheduleVideoUpdateModel extends Model {
return ScheduleVideoUpdateModel.findAll(query)
}
+ toFormattedJSON () {
+ return {
+ updateAt: this.updateAt,
+ privacy: this.privacy || undefined
+ }
+ }
}
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 440f4d171..0041e4d38 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -97,7 +97,8 @@ export enum ScopeNames {
AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
WITH_ACCOUNT_DETAILS = 'WITH_ACCOUNT_DETAILS',
WITH_TAGS = 'WITH_TAGS',
- WITH_FILES = 'WITH_FILES'
+ WITH_FILES = 'WITH_FILES',
+ WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE'
}
@Scopes({
@@ -286,6 +287,14 @@ export enum ScopeNames {
required: true
}
]
+ },
+ [ScopeNames.WITH_SCHEDULED_UPDATE]: {
+ include: [
+ {
+ model: () => ScheduleVideoUpdateModel.unscoped(),
+ required: false
+ }
+ ]
}
})
@Table({
@@ -843,7 +852,7 @@ export class VideoModel extends Model {
}
return VideoModel
- .scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT_DETAILS ])
+ .scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_SCHEDULED_UPDATE ])
.findById(id, options)
}
@@ -869,7 +878,7 @@ export class VideoModel extends Model {
}
return VideoModel
- .scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT_DETAILS ])
+ .scope([ ScopeNames.WITH_TAGS, ScopeNames.WITH_FILES, ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_SCHEDULED_UPDATE ])
.findOne(options)
}
@@ -1022,9 +1031,9 @@ export class VideoModel extends Model {
toFormattedJSON (options?: {
additionalAttributes: {
- state: boolean,
- waitTranscoding: boolean,
- scheduledUpdate: boolean
+ state?: boolean,
+ waitTranscoding?: boolean,
+ scheduledUpdate?: boolean
}
}): Video {
const formattedAccount = this.VideoChannel.Account.toFormattedJSON()
@@ -1084,18 +1093,18 @@ export class VideoModel extends Model {
}
if (options) {
- if (options.additionalAttributes.state) {
+ if (options.additionalAttributes.state === true) {
videoObject.state = {
id: this.state,
label: VideoModel.getStateLabel(this.state)
}
}
- if (options.additionalAttributes.waitTranscoding) {
+ if (options.additionalAttributes.waitTranscoding === true) {
videoObject.waitTranscoding = this.waitTranscoding
}
- if (options.additionalAttributes.scheduledUpdate && this.ScheduleVideoUpdate) {
+ if (options.additionalAttributes.scheduledUpdate === true && this.ScheduleVideoUpdate) {
videoObject.scheduledUpdate = {
updateAt: this.ScheduleVideoUpdate.updateAt,
privacy: this.ScheduleVideoUpdate.privacy || undefined
@@ -1107,7 +1116,11 @@ export class VideoModel extends Model {
}
toFormattedDetailsJSON (): VideoDetails {
- const formattedJson = this.toFormattedJSON()
+ const formattedJson = this.toFormattedJSON({
+ additionalAttributes: {
+ scheduledUpdate: true
+ }
+ })
const detailsJson = {
support: this.support,
diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts
index 04bed3b44..abbea6ba3 100644
--- a/server/tests/api/check-params/videos.ts
+++ b/server/tests/api/check-params/videos.ts
@@ -291,6 +291,23 @@ describe('Test videos API validator', function () {
await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
})
+ it('Should fail with a bad schedule update (miss updateAt)', async function () {
+ const fields = immutableAssign(baseCorrectParams, { 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC })
+ const attaches = baseCorrectAttaches
+
+ await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
+ })
+
+ it('Should fail with a bad schedule update (wrong updateAt)', async function () {
+ const fields = immutableAssign(baseCorrectParams, {
+ 'scheduleUpdate[privacy]': VideoPrivacy.PUBLIC,
+ 'scheduleUpdate[updateAt]': 'toto'
+ })
+ const attaches = baseCorrectAttaches
+
+ await makeUploadRequest({ url: server.url, path: path + '/upload', token: server.accessToken, fields, attaches })
+ })
+
it('Should fail without an input file', async function () {
const fields = baseCorrectParams
const attaches = {}
@@ -494,6 +511,18 @@ describe('Test videos API validator', function () {
await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
})
+ it('Should fail with a bad schedule update (miss updateAt)', async function () {
+ const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { privacy: VideoPrivacy.PUBLIC } })
+
+ await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
+ })
+
+ it('Should fail with a bad schedule update (wrong updateAt)', async function () {
+ const fields = immutableAssign(baseCorrectParams, { scheduleUpdate: { updateAt: 'toto', privacy: VideoPrivacy.PUBLIC } })
+
+ await makePutBodyRequest({ url: server.url, path: path + videoId, token: server.accessToken, fields })
+ })
+
it('Should fail with an incorrect thumbnail file', async function () {
const fields = baseCorrectParams
const attaches = {
diff --git a/server/tests/api/videos/video-schedule-update.ts b/server/tests/api/videos/video-schedule-update.ts
index 8b87ea855..a260fa4da 100644
--- a/server/tests/api/videos/video-schedule-update.ts
+++ b/server/tests/api/videos/video-schedule-update.ts
@@ -5,11 +5,14 @@ import 'mocha'
import { VideoPrivacy } from '../../../../shared/models/videos'
import {
doubleFollow,
- flushAndRunMultipleServers, getMyVideos,
+ flushAndRunMultipleServers,
+ getMyVideos,
getVideosList,
+ getVideoWithToken,
killallServers,
ServerInfo,
- setAccessTokensToServers, updateVideo,
+ setAccessTokensToServers,
+ updateVideo,
uploadVideo,
wait
} from '../../utils'
@@ -69,17 +72,22 @@ describe('Test video update scheduler', function () {
const res = await getMyVideos(servers[0].url, servers[0].accessToken, 0, 5)
expect(res.body.total).to.equal(1)
- const video = res.body.data[0]
- expect(video.name).to.equal('video 1')
- expect(video.privacy.id).to.equal(VideoPrivacy.PRIVATE)
- expect(new Date(video.scheduledUpdate.updateAt)).to.be.above(new Date())
- expect(video.scheduledUpdate.privacy).to.equal(VideoPrivacy.PUBLIC)
+ const videoFromList = res.body.data[0]
+ const res2 = await getVideoWithToken(servers[0].url, servers[0].accessToken, videoFromList.uuid)
+ const videoFromGet = res2.body
+
+ for (const video of [ videoFromList, videoFromGet ]) {
+ expect(video.name).to.equal('video 1')
+ expect(video.privacy.id).to.equal(VideoPrivacy.PRIVATE)
+ expect(new Date(video.scheduledUpdate.updateAt)).to.be.above(new Date())
+ expect(video.scheduledUpdate.privacy).to.equal(VideoPrivacy.PUBLIC)
+ }
})
it('Should wait some seconds and have the video in public privacy', async function () {
this.timeout(20000)
- await wait(10000)
+ await wait(15000)
await waitJobs(servers)
for (const server of servers) {
@@ -144,7 +152,7 @@ describe('Test video update scheduler', function () {
it('Should wait some seconds and have the updated video in public privacy', async function () {
this.timeout(20000)
- await wait(10000)
+ await wait(15000)
await waitJobs(servers)
for (const server of servers) {
diff --git a/shared/models/videos/video-create.model.ts b/shared/models/videos/video-create.model.ts
index 531eafe54..190d63783 100644
--- a/shared/models/videos/video-create.model.ts
+++ b/shared/models/videos/video-create.model.ts
@@ -1,4 +1,5 @@
import { VideoPrivacy } from './video-privacy.enum'
+import { VideoScheduleUpdate } from './video-schedule-update.model'
export interface VideoCreate {
category?: number
@@ -13,8 +14,5 @@ export interface VideoCreate {
tags?: string[]
commentsEnabled?: boolean
privacy: VideoPrivacy
- scheduleUpdate?: {
- updateAt: Date
- privacy?: VideoPrivacy.PUBLIC | VideoPrivacy.UNLISTED
- }
+ scheduleUpdate?: VideoScheduleUpdate
}
diff --git a/shared/models/videos/video-schedule-update.model.ts b/shared/models/videos/video-schedule-update.model.ts
new file mode 100644
index 000000000..b865c1614
--- /dev/null
+++ b/shared/models/videos/video-schedule-update.model.ts
@@ -0,0 +1,6 @@
+import { VideoPrivacy } from './video-privacy.enum'
+
+export interface VideoScheduleUpdate {
+ updateAt: Date | string
+ privacy?: VideoPrivacy.PUBLIC | VideoPrivacy.UNLISTED // Cannot schedule an update to PRIVATE
+}
diff --git a/shared/models/videos/video-update.model.ts b/shared/models/videos/video-update.model.ts
index fc0df6810..ed141a824 100644
--- a/shared/models/videos/video-update.model.ts
+++ b/shared/models/videos/video-update.model.ts
@@ -1,4 +1,5 @@
import { VideoPrivacy } from './video-privacy.enum'
+import { VideoScheduleUpdate } from './video-schedule-update.model'
export interface VideoUpdate {
name?: string
@@ -15,8 +16,5 @@ export interface VideoUpdate {
channelId?: number
thumbnailfile?: Blob
previewfile?: Blob
- scheduleUpdate?: {
- updateAt: Date
- privacy?: VideoPrivacy
- }
+ scheduleUpdate?: VideoScheduleUpdate
}
diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts
index 676354ce3..f88f381cb 100644
--- a/shared/models/videos/video.model.ts
+++ b/shared/models/videos/video.model.ts
@@ -3,6 +3,7 @@ import { Account } from '../actors'
import { Avatar } from '../avatars/avatar.model'
import { VideoChannel } from './video-channel.model'
import { VideoPrivacy } from './video-privacy.enum'
+import { VideoScheduleUpdate } from './video-schedule-update.model'
export interface VideoConstant {
id: T
@@ -43,10 +44,7 @@ export interface Video {
waitTranscoding?: boolean
state?: VideoConstant
- scheduledUpdate?: {
- updateAt: Date | string
- privacy?: VideoPrivacy
- }
+ scheduledUpdate?: VideoScheduleUpdate
account: {
id: number
diff --git a/support/doc/api/html/index.html b/support/doc/api/html/index.html
index e1bf61b06..24017e674 100644
--- a/support/doc/api/html/index.html
+++ b/support/doc/api/html/index.html
@@ -264,6 +264,7 @@
GetMeVideoRating
RegisterUser
VideoChannelInput
+ ScheduleVideoUpdate