Fix video_share_url duplicate key in transcoding job
authorChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 14:02:36 +0000 (15:02 +0100)
committerChocobozzz <me@florianbigard.com>
Mon, 19 Mar 2018 14:22:18 +0000 (15:22 +0100)
CHANGELOG.md
server/controllers/activitypub/inbox.ts
server/helpers/ffmpeg-utils.ts
server/initializers/constants.ts
server/lib/activitypub/share.ts
server/lib/job-queue/handlers/video-file.ts

index 04b8b7c3128d45251989f9c37b31877e8cf6352f..fb6ace20e173f491c0b53aadabf34d62d7d0559e 100644 (file)
@@ -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
    * 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
index 0354d783369615d828a1ed958998afaca1d5f5f6..df041aebf6c72fc22b7556576b11fe8e9446d0b7 100644 (file)
@@ -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)
 
index 4f75ba5a82606b5089a59b6693242207bd25b1c3..4d6cd3a826f5b9a8049b6e5b7a383d7c2745e434 100644 (file)
@@ -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
index d12d968032bc45939fd038b9ab730f5d0b4b7878..3cf9ea36d74c707fb93d6e11b960ce56903063a7 100644 (file)
@@ -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,
index 53ecd3dab7a857b40c95dd28c5b663b00fd1ac84..038f19b7dadc5bd416b65f8445e7b589e8ed93b1 100644 (file)
@@ -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
   ])
 }
 
index bd9412290ac1c34582b8bafe1b1392541cdb4784..1b41d29e862baa413ce17c6f8cc8415d129ce7ba 100644 (file)
@@ -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<any>[] = []
-
-        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 tasks: Promise<any>[] = []
+
+    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 })
   } else {
     logger.info('No transcoding jobs created for video %s (no resolutions enabled).')
     return undefined