From f713f36bdf6f696ab0fe8a309035a09e864a48ca Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 14 Nov 2022 12:06:31 +0100 Subject: [PATCH] Federate entire description Introduce an explicit field truncatedDescription description in video list is deprecated description in video get will contain the entire description --- .../metadata/video-description.component.html | 2 +- .../metadata/video-description.component.ts | 39 ++++++++++++------- .../shared/shared-main/video/video.model.ts | 3 ++ .../custom-validators/activitypub/videos.ts | 10 ++--- server/helpers/custom-validators/videos.ts | 5 --- .../video/formatter/video-format-utils.ts | 2 + server/tests/api/videos/video-description.ts | 23 ++++++++--- shared/models/videos/video.model.ts | 6 +++ 8 files changed, 58 insertions(+), 32 deletions(-) diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.html b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.html index fa4dbb3ca..d847daff7 100644 --- a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.html +++ b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.html @@ -1,7 +1,7 @@
diff --git a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts index 72b09a274..d01080611 100644 --- a/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts +++ b/client/src/app/+videos/+video-watch/shared/metadata/video-description.component.ts @@ -15,8 +15,10 @@ export class VideoDescriptionComponent implements OnChanges { descriptionLoading = false completeDescriptionShown = false - completeVideoDescription: string - shortVideoDescription: string + + completeVideoDescriptionLoaded = false + + videoHTMLTruncatedDescription = '' videoHTMLDescription = '' constructor ( @@ -28,22 +30,19 @@ export class VideoDescriptionComponent implements OnChanges { ngOnChanges () { this.descriptionLoading = false this.completeDescriptionShown = false - this.completeVideoDescription = undefined this.setVideoDescriptionHTML() } showMoreDescription () { - if (this.completeVideoDescription === undefined) { + if (!this.completeVideoDescriptionLoaded) { return this.loadCompleteDescription() } - this.updateVideoDescription(this.completeVideoDescription) this.completeDescriptionShown = true } showLessDescription () { - this.updateVideoDescription(this.shortVideoDescription) this.completeDescriptionShown = false } @@ -56,10 +55,10 @@ export class VideoDescriptionComponent implements OnChanges { this.completeDescriptionShown = true this.descriptionLoading = false - this.shortVideoDescription = this.video.description - this.completeVideoDescription = description + this.video.description = description - this.updateVideoDescription(this.completeVideoDescription) + this.setVideoDescriptionHTML() + .catch(err => logger.error(err)) }, error: err => { @@ -73,15 +72,25 @@ export class VideoDescriptionComponent implements OnChanges { this.timestampClicked.emit(timestamp) } - private updateVideoDescription (description: string) { - this.video.description = description - this.setVideoDescriptionHTML() - .catch(err => logger.error(err)) + getHTMLDescription () { + if (this.completeDescriptionShown) { + return this.videoHTMLDescription + } + + return this.videoHTMLTruncatedDescription } private async setVideoDescriptionHTML () { - const html = await this.markdownService.textMarkdownToHTML({ markdown: this.video.description }) + { + const html = await this.markdownService.textMarkdownToHTML({ markdown: this.video.description }) - this.videoHTMLDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html) + this.videoHTMLDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html) + } + + { + const html = await this.markdownService.textMarkdownToHTML({ markdown: this.video.truncatedDescription }) + + this.videoHTMLTruncatedDescription = this.markdownService.processVideoTimestamps(this.video.shortUUID, html) + } } } diff --git a/client/src/app/shared/shared-main/video/video.model.ts b/client/src/app/shared/shared-main/video/video.model.ts index c9c6b979c..6fdffb394 100644 --- a/client/src/app/shared/shared-main/video/video.model.ts +++ b/client/src/app/shared/shared-main/video/video.model.ts @@ -34,6 +34,7 @@ export class Video implements VideoServerModel { language: VideoConstant privacy: VideoConstant + truncatedDescription: string description: string duration: number @@ -134,6 +135,8 @@ export class Video implements VideoServerModel { this.privacy = hash.privacy this.waitTranscoding = hash.waitTranscoding this.state = hash.state + + this.truncatedDescription = hash.truncatedDescription this.description = hash.description this.isLive = hash.isLive diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index 2a2f008b9..97b3577af 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts @@ -7,11 +7,11 @@ import { peertubeTruncate } from '../../core-utils' import { isArray, isBooleanValid, isDateValid, isUUIDValid } from '../misc' import { isLiveLatencyModeValid } from '../video-lives' import { + isVideoDescriptionValid, isVideoDurationValid, isVideoNameValid, isVideoStateValid, isVideoTagValid, - isVideoTruncatedDescriptionValid, isVideoViewsValid } from '../videos' import { isActivityPubUrlValid, isActivityPubVideoDurationValid, isBaseActivityValid, setValidAttributedTo } from './misc' @@ -32,7 +32,7 @@ function sanitizeAndCheckVideoTorrentObject (video: any) { logger.debug('Video has invalid urls', { video }) return false } - if (!setRemoteVideoTruncatedContent(video)) { + if (!setRemoteVideoContent(video)) { logger.debug('Video has invalid content', { video }) return false } @@ -168,7 +168,7 @@ function isRemoteStringIdentifierValid (data: any) { } function isRemoteVideoContentValid (mediaType: string, content: string) { - return mediaType === 'text/markdown' && isVideoTruncatedDescriptionValid(content) + return mediaType === 'text/markdown' && isVideoDescriptionValid(content) } function setValidRemoteIcon (video: any) { @@ -194,9 +194,9 @@ function setValidRemoteVideoUrls (video: any) { return true } -function setRemoteVideoTruncatedContent (video: any) { +function setRemoteVideoContent (video: any) { if (video.content) { - video.content = peertubeTruncate(video.content, { length: CONSTRAINTS_FIELDS.VIDEOS.TRUNCATED_DESCRIPTION.max }) + video.content = peertubeTruncate(video.content, { length: CONSTRAINTS_FIELDS.VIDEOS.DESCRIPTION.max }) } return true diff --git a/server/helpers/custom-validators/videos.ts b/server/helpers/custom-validators/videos.ts index 3ebfe2937..9e8177f77 100644 --- a/server/helpers/custom-validators/videos.ts +++ b/server/helpers/custom-validators/videos.ts @@ -45,10 +45,6 @@ function isVideoDurationValid (value: string) { return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION) } -function isVideoTruncatedDescriptionValid (value: string) { - return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION) -} - function isVideoDescriptionValid (value: string) { return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)) } @@ -151,7 +147,6 @@ export { isVideoCategoryValid, isVideoLicenceValid, isVideoLanguageValid, - isVideoTruncatedDescriptionValid, isVideoDescriptionValid, isVideoFileInfoHashValid, isVideoNameValid, diff --git a/server/models/video/formatter/video-format-utils.ts b/server/models/video/formatter/video-format-utils.ts index 76745f4b5..240619f69 100644 --- a/server/models/video/formatter/video-format-utils.ts +++ b/server/models/video/formatter/video-format-utils.ts @@ -103,6 +103,7 @@ function videoModelToFormattedJSON (video: MVideoFormattable, options: VideoForm }, nsfw: video.nsfw, + truncatedDescription: video.getTruncatedDescription(), description: options && options.completeDescription === true ? video.description : video.getTruncatedDescription(), @@ -181,6 +182,7 @@ function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): Vid const span = tracer.startSpan('peertube.VideoModel.toFormattedDetailsJSON') const videoJSON = video.toFormattedJSON({ + completeDescription: true, additionalAttributes: { scheduledUpdate: true, blacklistInfo: true, diff --git a/server/tests/api/videos/video-description.ts b/server/tests/api/videos/video-description.ts index a4b3ff6e7..c4185882a 100644 --- a/server/tests/api/videos/video-description.ts +++ b/server/tests/api/videos/video-description.ts @@ -14,8 +14,12 @@ describe('Test video description', function () { let servers: PeerTubeServer[] = [] let videoUUID = '' let videoId: number + const longDescription = 'my super description for server 1'.repeat(50) + // 30 characters * 6 -> 240 characters + const truncatedDescription = 'my super description for server 1'.repeat(7) + 'my super descrip...' + before(async function () { this.timeout(40000) @@ -45,15 +49,22 @@ describe('Test video description', function () { videoUUID = data[0].uuid }) - it('Should have a truncated description on each server', async function () { + it('Should have a truncated description on each server when listing videos', async function () { for (const server of servers) { - const video = await server.videos.get({ id: videoUUID }) - - // 30 characters * 6 -> 240 characters - const truncatedDescription = 'my super description for server 1'.repeat(7) + - 'my super descrip...' + const { data } = await server.videos.list() + const video = data.find(v => v.uuid === videoUUID) expect(video.description).to.equal(truncatedDescription) + expect(video.truncatedDescription).to.equal(truncatedDescription) + } + }) + + it('Should not have a truncated description on each server when getting videos', async function () { + for (const server of servers) { + const video = await server.videos.get({ id: videoUUID }) + + expect(video.description).to.equal(longDescription) + expect(video.truncatedDescription).to.equal(truncatedDescription) } }) diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts index d9765dbd6..06ffb327c 100644 --- a/shared/models/videos/video.model.ts +++ b/shared/models/videos/video.model.ts @@ -20,7 +20,11 @@ export interface Video { licence: VideoConstant language: VideoConstant privacy: VideoConstant + + // Deprecated in 5.0 in favour of truncatedDescription description: string + truncatedDescription: string + duration: number isLocal: boolean name: string @@ -70,7 +74,9 @@ export interface Video { } export interface VideoDetails extends Video { + // Deprecated in 5.0 descriptionPath: string + support: string channel: VideoChannel account: Account -- 2.41.0