diff --git a/CHANGELOG.md b/CHANGELOG.md index 04b8b7c31..fb6ace20e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### BREAKING CHANGES -* Update videos list/search/get API response: + * Update videos list/search/get API response: * Removed `resolution` field * Removed `resolutionLabel` field * Removed `category` field @@ -26,6 +26,10 @@ * Added `privacy.id` field * Added `privacy.label` field +### Bug fixes + + * Fix video_share_url duplicate key on failed transcoding job + ## v1.0.0-alpha.8 @@ -60,8 +64,7 @@ ### Features - * Add "Local" in menu that lists only local videos - + * Add "Local" in menu that lists only local videos ## v1.0.0-alpha.4 diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index 0354d7833..df041aebf 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts @@ -56,7 +56,7 @@ async function inboxController (req: express.Request, res: express.Response, nex specificActor = res.locals.videoChannel } - logger.info('Receiving inbox requests for %d activities by %s.', activities.length, res.locals.signature.actor) + logger.info('Receiving inbox requests for %d activities by %s.', activities.length, res.locals.signature.actor.url) await processActivities(activities, res.locals.signature.actor, specificActor) diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 4f75ba5a8..4d6cd3a82 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts @@ -1,7 +1,7 @@ import * as ffmpeg from 'fluent-ffmpeg' import { join } from 'path' import { VideoResolution } from '../../shared/models/videos' -import { CONFIG, MAX_VIDEO_TRANSCODING_FPS } from '../initializers' +import { CONFIG, VIDEO_TRANSCODING_FPS } from '../initializers' import { unlinkPromise } from './core-utils' import { processImage } from './image-utils' import { logger } from './logger' @@ -92,7 +92,9 @@ function transcode (options: TranscodeOptions) { .outputOption('-movflags faststart') // .outputOption('-crf 18') - if (fps > MAX_VIDEO_TRANSCODING_FPS) command = command.withFPS(MAX_VIDEO_TRANSCODING_FPS) + // Our player has some FPS limits + if (fps > VIDEO_TRANSCODING_FPS.MAX) command = command.withFPS(VIDEO_TRANSCODING_FPS.MAX) + else if (fps < VIDEO_TRANSCODING_FPS.MIN) command = command.withFPS(VIDEO_TRANSCODING_FPS.MIN) if (options.resolution !== undefined) { // '?x720' or '720x?' for example diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index d12d96803..3cf9ea36d 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts @@ -234,7 +234,10 @@ const CONSTRAINTS_FIELDS = { } let VIDEO_VIEW_LIFETIME = 60000 * 60 // 1 hour -const MAX_VIDEO_TRANSCODING_FPS = 30 +const VIDEO_TRANSCODING_FPS = { + MIN: 10, + MAX: 30 +} const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = { LIKE: 'like', @@ -445,7 +448,7 @@ export { VIDEO_LICENCES, VIDEO_RATE_TYPES, VIDEO_MIMETYPE_EXT, - MAX_VIDEO_TRANSCODING_FPS, + VIDEO_TRANSCODING_FPS, USER_PASSWORD_RESET_LIFETIME, IMAGE_MIMETYPE_EXT, SCHEDULER_INTERVAL, diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index 53ecd3dab..038f19b7d 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts @@ -12,27 +12,42 @@ async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) const serverActor = await getServerActor() const serverShareUrl = getAnnounceActivityPubUrl(video.url, serverActor) - const serverSharePromise = VideoShareModel.create({ - actorId: serverActor.id, - videoId: video.id, - url: serverShareUrl - }, { transaction: t }) + const serverSharePromise = VideoShareModel.findOrCreate({ + defaults: { + actorId: serverActor.id, + videoId: video.id, + url: serverShareUrl + }, + where: { + url: serverShareUrl + }, + transaction: t + }).then(([ serverShare, created ]) => { + if (created) return sendVideoAnnounceToFollowers(serverActor, serverShare, video, t) + + return undefined + }) const videoChannelShareUrl = getAnnounceActivityPubUrl(video.url, video.VideoChannel.Actor) - const videoChannelSharePromise = VideoShareModel.create({ - actorId: video.VideoChannel.actorId, - videoId: video.id, - url: videoChannelShareUrl - }, { transaction: t }) + const videoChannelSharePromise = VideoShareModel.findOrCreate({ + defaults: { + actorId: video.VideoChannel.actorId, + videoId: video.id, + url: videoChannelShareUrl + }, + where: { + url: videoChannelShareUrl + }, + transaction: t + }).then(([ videoChannelShare, created ]) => { + if (created) return sendVideoAnnounceToFollowers(serverActor, videoChannelShare, video, t) - const [ serverShare, videoChannelShare ] = await Promise.all([ - serverSharePromise, - videoChannelSharePromise - ]) + return undefined + }) return Promise.all([ - sendVideoAnnounceToFollowers(serverActor, videoChannelShare, video, t), - sendVideoAnnounceToFollowers(serverActor, serverShare, video, t) + serverSharePromise, + videoChannelSharePromise ]) } diff --git a/server/lib/job-queue/handlers/video-file.ts b/server/lib/job-queue/handlers/video-file.ts index bd9412290..1b41d29e8 100644 --- a/server/lib/job-queue/handlers/video-file.ts +++ b/server/lib/job-queue/handlers/video-file.ts @@ -63,8 +63,10 @@ async function onVideoFileOptimizerSuccess (video: VideoModel) { if (video.privacy !== VideoPrivacy.PRIVATE) { // Now we'll add the video's meta data to our followers - await sendCreateVideo(video, undefined) - await shareVideoByServerAndChannel(video, undefined) + await sequelizeTypescript.transaction(async t => { + await sendCreateVideo(video, t) + await shareVideoByServerAndChannel(video, t) + }) } const { videoFileResolution } = await videoDatabase.getOriginalFileResolution() @@ -77,27 +79,21 @@ async function onVideoFileOptimizerSuccess (video: VideoModel) { ) if (resolutionsEnabled.length !== 0) { - try { - await sequelizeTypescript.transaction(async t => { - const tasks: Promise[] = [] + const tasks: Promise[] = [] - for (const resolution of resolutionsEnabled) { - const dataInput = { - videoUUID: videoDatabase.uuid, - resolution - } + for (const resolution of resolutionsEnabled) { + const dataInput = { + videoUUID: videoDatabase.uuid, + resolution + } - const p = JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput }) - tasks.push(p) - } - - await Promise.all(tasks) - }) - - logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) - } catch (err) { - logger.warn('Cannot transcode the video.', err) + const p = JobQueue.Instance.createJob({ type: 'video-file', payload: dataInput }) + tasks.push(p) } + + await Promise.all(tasks) + + logger.info('Transcoding jobs created for uuid %s.', videoDatabase.uuid, { resolutionsEnabled }) } else { logger.info('No transcoding jobs created for video %s (no resolutions enabled).') return undefined