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
-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,
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())
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'
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'
-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,
ActivitypubHttpFetcherPayload,
ActivityTagObject,
ActivityUrlObject,
- ActivityVideoUrlObject,
- VideoState
+ ActivityVideoUrlObject
} from '../../../shared/index'
import { VideoObject } from '../../../shared/models/activitypub/objects'
import { VideoPrivacy } from '../../../shared/models/videos'
return url && url.type === 'Hashtag'
}
-
-
async function createVideo (videoObject: VideoObject, channel: MChannelAccountLight, waitThumbnail = false) {
logger.debug('Adding remote video %s.', videoObject.id)
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
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)
}
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'
function getVideoFilename (videoOrPlaylist: MVideo | MStreamingPlaylistVideo, videoFile: MVideoFile) {
const video = extractVideo(videoOrPlaylist)
- if (isStreamingPlaylist(videoOrPlaylist)) {
+ if (videoFile.isHLS()) {
return generateVideoStreamingPlaylistName(video.uuid, videoFile.resolution)
}
}
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))
-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,
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.
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'
return this.size === -1
}
+ isHLS () {
+ return this.videoStreamingPlaylistId !== null
+ }
+
hasSameUniqueKeysThan (other: MVideoFile) {
return this.fps === other.fps &&
this.resolution === other.resolution &&
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,
testImage,
updateCustomSubConfig,
updateLive,
- userLogin,
waitJobs,
waitUntilLiveStarts
} from '../../../../shared/extra-utils'
describe('Test live', function () {
let servers: ServerInfo[] = []
- let userId: number
- let userAccessToken: string
- let userChannelId: number
before(async function () {
this.timeout(120000)
}
})
- {
- 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])
})