From: Chocobozzz Date: Fri, 6 Nov 2020 09:57:40 +0000 (+0100) Subject: Regenerate miniature on live save X-Git-Tag: v3.0.0-rc.1~404 X-Git-Url: https://git.immae.eu/?a=commitdiff_plain;h=053aed43fb255b4ae4324a845534f2f562c3b6cc;hp=3bc68dfd6183078fb56b53e24e74f889c85c4ae0;p=github%2FChocobozzz%2FPeerTube.git Regenerate miniature on live save --- diff --git a/client/src/assets/player/peertube-player-manager.ts b/client/src/assets/player/peertube-player-manager.ts index 3d72d4609..c1953043e 100644 --- a/client/src/assets/player/peertube-player-manager.ts +++ b/client/src/assets/player/peertube-player-manager.ts @@ -339,10 +339,8 @@ export class PeertubePlayerManager { const resolution = Math.min(level.height || 0, level.width || 0) const file = p2pMediaLoaderOptions.videoFiles.find(f => f.resolution.id === resolution) - if (!file) { - console.error('Cannot find video file for level %d.', level.height) - return level.height - } + // We don't have files for live videos + if (!file) return level.height let label = file.resolution.label if (file.fps >= 50) label += file.fps diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index df2a01d2c..d85d0aa5f 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts @@ -1,11 +1,22 @@ -import * as express from 'express' import * as cors from 'cors' +import * as express from 'express' +import { getRateUrl } from '@server/lib/activitypub/video-rates' +import { getServerActor } from '@server/models/application/application' +import { MAccountId, MActorId, MChannelId, MVideoId } from '@server/types/models' import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' +import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../../initializers/constants' -import { buildAnnounceWithVideoAudience, buildLikeActivity } from '../../lib/activitypub/send' import { audiencify, getAudience } from '../../lib/activitypub/audience' +import { buildAnnounceWithVideoAudience, buildLikeActivity } from '../../lib/activitypub/send' import { buildCreateActivity } from '../../lib/activitypub/send/send-create' +import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike' +import { + getVideoCommentsActivityPubUrl, + getVideoDislikesActivityPubUrl, + getVideoLikesActivityPubUrl, + getVideoSharesActivityPubUrl +} from '../../lib/activitypub/url' import { asyncMiddleware, executeIfActivityPub, @@ -14,30 +25,19 @@ import { videosCustomGetValidator, videosShareValidator } from '../../middlewares' +import { cacheRoute } from '../../middlewares/cache' import { getAccountVideoRateValidatorFactory, videoCommentGetValidator } from '../../middlewares/validators' +import { videoFileRedundancyGetValidator, videoPlaylistRedundancyGetValidator } from '../../middlewares/validators/redundancy' +import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists' import { AccountModel } from '../../models/account/account' +import { AccountVideoRateModel } from '../../models/account/account-video-rate' import { ActorFollowModel } from '../../models/activitypub/actor-follow' import { VideoModel } from '../../models/video/video' +import { VideoCaptionModel } from '../../models/video/video-caption' import { VideoCommentModel } from '../../models/video/video-comment' +import { VideoPlaylistModel } from '../../models/video/video-playlist' import { VideoShareModel } from '../../models/video/video-share' -import { cacheRoute } from '../../middlewares/cache' import { activityPubResponse } from './utils' -import { AccountVideoRateModel } from '../../models/account/account-video-rate' -import { - getVideoCommentsActivityPubUrl, - getVideoDislikesActivityPubUrl, - getVideoLikesActivityPubUrl, - getVideoSharesActivityPubUrl -} from '../../lib/activitypub/url' -import { VideoCaptionModel } from '../../models/video/video-caption' -import { videoFileRedundancyGetValidator, videoPlaylistRedundancyGetValidator } from '../../middlewares/validators/redundancy' -import { buildDislikeActivity } from '../../lib/activitypub/send/send-dislike' -import { videoPlaylistElementAPGetValidator, videoPlaylistsGetValidator } from '../../middlewares/validators/videos/video-playlists' -import { VideoPlaylistModel } from '../../models/video/video-playlist' -import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' -import { MAccountId, MActorId, MVideoAPWithoutCaption, MVideoId, MChannelId } from '@server/types/models' -import { getServerActor } from '@server/models/application/application' -import { getRateUrl } from '@server/lib/activitypub/video-rates' const activityPubClientRouter = express.Router() activityPubClientRouter.use(cors()) diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 50e769e77..ff29e584b 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts @@ -9,7 +9,7 @@ import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' import { buildLocalVideoFromReq, buildVideoThumbnailsFromReq, setVideoTags } from '@server/lib/video' import { getVideoFilePath } from '@server/lib/video-paths' import { getServerActor } from '@server/models/application/application' -import { MVideoDetails, MVideoFullLight } from '@server/types/models' +import { MVideoFullLight } from '@server/types/models' import { VideoCreate, VideoState, VideoUpdate } from '../../../../shared' import { VideoFilter } from '../../../../shared/models/videos/video-query.type' import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 7a54b4642..b6f4097aa 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -1,5 +1,5 @@ import * as ffmpeg from 'fluent-ffmpeg' -import { outputFile, readFile, remove, writeFile } from 'fs-extra' +import { readFile, remove, writeFile } from 'fs-extra' import { dirname, join } from 'path' import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata' import { getMaxBitrate, getTargetBitrate, VideoResolution } from '../../shared/models/videos' diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index ab4aac0a1..4053f487c 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -1,10 +1,10 @@ -import { VideoLiveModel } from '@server/models/video/video-live' import * as Bluebird from 'bluebird' import { maxBy, minBy } from 'lodash' import * as magnetUtil from 'magnet-uri' import { join } from 'path' import * as request from 'request' import * as sequelize from 'sequelize' +import { VideoLiveModel } from '@server/models/video/video-live' import { ActivityHashTagObject, ActivityMagnetUrlObject, @@ -13,8 +13,7 @@ import { ActivitypubHttpFetcherPayload, ActivityTagObject, ActivityUrlObject, - ActivityVideoUrlObject, - VideoState + ActivityVideoUrlObject } from '../../../shared/index' import { VideoObject } from '../../../shared/models/activitypub/objects' import { VideoPrivacy } from '../../../shared/models/videos' @@ -562,8 +561,6 @@ function isAPHashTagObject (url: any): url is ActivityHashTagObject { return url && url.type === 'Hashtag' } - - async function createVideo (videoObject: VideoObject, channel: MChannelAccountLight, waitThumbnail = false) { logger.debug('Adding remote video %s.', videoObject.id) diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts index 3892260c4..3d9341738 100644 --- a/server/lib/job-queue/handlers/video-live-ending.ts +++ b/server/lib/job-queue/handlers/video-live-ending.ts @@ -10,8 +10,9 @@ import { VideoFileModel } from '@server/models/video/video-file' import { VideoLiveModel } from '@server/models/video/video-live' import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' import { MStreamingPlaylist, MVideo, MVideoLive } from '@server/types/models' -import { VideoLiveEndingPayload, VideoState } from '@shared/models' +import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' import { logger } from '../../../helpers/logger' +import { generateVideoMiniature } from '@server/lib/thumbnail' async function processVideoLiveEnding (job: Bull.Job) { const payload = job.data as VideoLiveEndingPayload @@ -109,6 +110,15 @@ async function saveLive (video: MVideo, live: MVideoLive) { await remove(videoInputPath) } + // Regenerate the thumbnail & preview? + if (videoWithFiles.getMiniature().automaticallyGenerated === true) { + await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.MINIATURE) + } + + if (videoWithFiles.getPreview().automaticallyGenerated === true) { + await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.PREVIEW) + } + await publishAndFederateIfNeeded(video, true) } diff --git a/server/lib/live-manager.ts b/server/lib/live-manager.ts index d253d06fc..9a2914cc5 100644 --- a/server/lib/live-manager.ts +++ b/server/lib/live-manager.ts @@ -4,7 +4,13 @@ import * as chokidar from 'chokidar' import { FfmpegCommand } from 'fluent-ffmpeg' import { ensureDir, stat } from 'fs-extra' import { basename } from 'path' -import { computeResolutionsToTranscode, getVideoFileFPS, getVideoFileResolution, getVideoStreamCodec, getVideoStreamSize, runLiveMuxing, runLiveTranscoding } from '@server/helpers/ffmpeg-utils' +import { + computeResolutionsToTranscode, + getVideoFileFPS, + getVideoFileResolution, + runLiveMuxing, + runLiveTranscoding +} from '@server/helpers/ffmpeg-utils' import { logger } from '@server/helpers/logger' import { CONFIG, registerConfigChangedHandler } from '@server/initializers/config' import { MEMOIZE_TTL, P2P_MEDIA_LOADER_PEER_VERSION, VIDEO_LIVE, WEBSERVER } from '@server/initializers/constants' diff --git a/server/lib/video-paths.ts b/server/lib/video-paths.ts index b6cb39d25..53fc8e81d 100644 --- a/server/lib/video-paths.ts +++ b/server/lib/video-paths.ts @@ -9,7 +9,7 @@ import { extractVideo } from '@server/helpers/video' function getVideoFilename (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) { const video = extractVideo(videoOrPlaylist) - if (isStreamingPlaylist(videoOrPlaylist)) { + if (videoFile.isHLS()) { return generateVideoStreamingPlaylistName(video.uuid, videoFile.resolution) } @@ -25,7 +25,7 @@ function generateWebTorrentVideoName (uuid: string, resolution: number, extname: } function getVideoFilePath (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile, isRedundancy = false) { - if (isStreamingPlaylist(videoOrPlaylist)) { + if (videoFile.isHLS()) { const video = extractVideo(videoOrPlaylist) return join(getHLSDirectory(video), getVideoFilename(videoOrPlaylist, videoFile)) diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index c62b3c1ce..e267b1397 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts @@ -1,5 +1,9 @@ -import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' +import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' import { basename, extname as extnameUtil, join } from 'path' +import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' +import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models' +import { VideoResolution } from '../../shared/models/videos' +import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' import { canDoQuickTranscode, getDurationFromVideoFile, @@ -9,18 +13,13 @@ import { TranscodeOptions, TranscodeOptionsType } from '../helpers/ffmpeg-utils' -import { copyFile, ensureDir, move, remove, stat } from 'fs-extra' import { logger } from '../helpers/logger' -import { VideoResolution } from '../../shared/models/videos' +import { CONFIG } from '../initializers/config' +import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION, WEBSERVER } from '../initializers/constants' import { VideoFileModel } from '../models/video/video-file' -import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' -import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' -import { CONFIG } from '../initializers/config' -import { MStreamingPlaylistFilesVideo, MVideoFile, MVideoWithAllFiles, MVideoWithFile } from '@server/types/models' -import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' +import { updateMasterHLSPlaylist, updateSha256VODSegments } from './hls' import { generateVideoStreamingPlaylistName, getVideoFilename, getVideoFilePath } from './video-paths' -import { spawn } from 'child_process' /** * Optimize the original video file and replace it. The resolution is not changed. diff --git a/server/lib/video.ts b/server/lib/video.ts index 8d9918b2d..d03ab0452 100644 --- a/server/lib/video.ts +++ b/server/lib/video.ts @@ -4,7 +4,7 @@ import { TagModel } from '@server/models/video/tag' import { VideoModel } from '@server/models/video/video' import { FilteredModelAttributes } from '@server/types' import { MTag, MThumbnail, MVideoTag, MVideoThumbnail, MVideoUUID } from '@server/types/models' -import { ThumbnailType, VideoCreate, VideoPrivacy, VideoState } from '@shared/models' +import { ThumbnailType, VideoCreate, VideoPrivacy } from '@shared/models' import { federateVideoIfNeeded } from './activitypub/videos' import { Notifier } from './notifier' import { createVideoMiniatureFromExisting } from './thumbnail' diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index 5048cf9b7..0e834aee0 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts @@ -333,6 +333,10 @@ export class VideoFileModel extends Model { return this.size === -1 } + isHLS () { + return this.videoStreamingPlaylistId !== null + } + hasSameUniqueKeysThan (other: MVideoFile) { return this.fps === other.fps && this.resolution === other.resolution && diff --git a/server/tests/api/live/live.ts b/server/tests/api/live/live.ts index c795f201a..b41b5fc2e 100644 --- a/server/tests/api/live/live.ts +++ b/server/tests/api/live/live.ts @@ -3,18 +3,16 @@ import 'mocha' import * as chai from 'chai' import { getLiveNotificationSocket } from '@shared/extra-utils/socket/socket-io' -import { LiveVideo, LiveVideoCreate, User, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' +import { LiveVideo, LiveVideoCreate, Video, VideoDetails, VideoPrivacy, VideoState, VideoStreamingPlaylistType } from '@shared/models' import { addVideoToBlacklist, checkLiveCleanup, checkResolutionsInMasterPlaylist, cleanupTests, createLive, - createUser, doubleFollow, flushAndRunMultipleServers, getLive, - getMyUserInformation, getVideo, getVideoIdFromUUID, getVideosList, @@ -30,7 +28,6 @@ import { testImage, updateCustomSubConfig, updateLive, - userLogin, waitJobs, waitUntilLiveStarts } from '../../../../shared/extra-utils' @@ -39,9 +36,6 @@ const expect = chai.expect describe('Test live', function () { let servers: ServerInfo[] = [] - let userId: number - let userAccessToken: string - let userChannelId: number before(async function () { this.timeout(120000) @@ -62,22 +56,6 @@ describe('Test live', function () { } }) - { - const user = { username: 'user1', password: 'superpassword' } - const res = await createUser({ - url: servers[0].url, - accessToken: servers[0].accessToken, - username: user.username, - password: user.password - }) - userId = res.body.user.id - - userAccessToken = await userLogin(servers[0], user) - - const resMe = await getMyUserInformation(servers[0].url, userAccessToken) - userChannelId = (resMe.body as User).videoChannels[0].id - } - // Server 1 and server 2 follow each other await doubleFollow(servers[0], servers[1]) })