aboutsummaryrefslogblamecommitdiffhomepage
path: root/server/tests/api/videos/video-storyboard.ts
blob: fc4b4450ff546d3bec9f238f7fa85ee26f2e16dd (plain) (tree)
1
2
3
4
5


                                                                                              

                                  














































                                                                                                                                    

                      














                                                                                                         
                   









































                                                                                                                




                                                                                                                  


































































                                                                                                    
                                                                        

                       



















                                                                              





                               
/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */

import { expect } from 'chai'
import { readdir } from 'fs-extra'
import { basename } from 'path'
import { FIXTURE_URLS } from '@server/tests/shared'
import { areHttpImportTestsDisabled } from '@shared/core-utils'
import { HttpStatusCode, VideoPrivacy } from '@shared/models'
import {
  cleanupTests,
  createMultipleServers,
  doubleFollow,
  makeGetRequest,
  PeerTubeServer,
  sendRTMPStream,
  setAccessTokensToServers,
  setDefaultVideoChannel,
  stopFfmpeg,
  waitJobs
} from '@shared/server-commands'

async function checkStoryboard (options: {
  server: PeerTubeServer
  uuid: string
  tilesCount?: number
  minSize?: number
}) {
  const { server, uuid, tilesCount, minSize = 1000 } = options

  const { storyboards } = await server.storyboard.list({ id: uuid })

  expect(storyboards).to.have.lengthOf(1)

  const storyboard = storyboards[0]

  expect(storyboard.spriteDuration).to.equal(1)
  expect(storyboard.spriteHeight).to.equal(108)
  expect(storyboard.spriteWidth).to.equal(192)
  expect(storyboard.storyboardPath).to.exist

  if (tilesCount) {
    expect(storyboard.totalWidth).to.equal(192 * Math.min(tilesCount, 10))
    expect(storyboard.totalHeight).to.equal(108 * Math.max((tilesCount / 10), 1))
  }

  const { body } = await makeGetRequest({ url: server.url, path: storyboard.storyboardPath, expectedStatus: HttpStatusCode.OK_200 })
  expect(body.length).to.be.above(minSize)
}

describe('Test video storyboard', function () {
  let servers: PeerTubeServer[]

  let baseUUID: string

  before(async function () {
    this.timeout(120000)

    servers = await createMultipleServers(2)
    await setAccessTokensToServers(servers)
    await setDefaultVideoChannel(servers)

    await doubleFollow(servers[0], servers[1])
  })

  it('Should generate a storyboard after upload without transcoding', async function () {
    this.timeout(60000)

    // 5s video
    const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_short.webm' })
    baseUUID = uuid
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid, tilesCount: 5 })
    }
  })

  it('Should generate a storyboard after upload without transcoding with a long video', async function () {
    this.timeout(60000)

    // 124s video
    const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_very_long_10p.mp4' })
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid, tilesCount: 100 })
    }
  })

  it('Should generate a storyboard after upload with transcoding', async function () {
    this.timeout(60000)

    await servers[0].config.enableMinimumTranscoding()

    // 5s video
    const { uuid } = await servers[0].videos.quickUpload({ name: 'upload', fixture: 'video_short.webm' })
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid, tilesCount: 5 })
    }
  })

  it('Should generate a storyboard after an audio upload', async function () {
    this.timeout(60000)

    // 6s audio
    const attributes = { name: 'audio', fixture: 'sample.ogg' }
    const { uuid } = await servers[0].videos.upload({ attributes, mode: 'legacy' })
    await waitJobs(servers)

    for (const server of servers) {
      try {
        await checkStoryboard({ server, uuid, tilesCount: 6, minSize: 250 })
      } catch { // FIXME: to remove after ffmpeg CI upgrade, ffmpeg CI version (4.3) generates a 7.6s length video
        await checkStoryboard({ server, uuid, tilesCount: 8, minSize: 250 })
      }
    }
  })

  it('Should generate a storyboard after HTTP import', async function () {
    this.timeout(60000)

    if (areHttpImportTestsDisabled()) return

    // 3s video
    const { video } = await servers[0].imports.importVideo({
      attributes: {
        targetUrl: FIXTURE_URLS.goodVideo,
        channelId: servers[0].store.channel.id,
        privacy: VideoPrivacy.PUBLIC
      }
    })
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid: video.uuid, tilesCount: 3 })
    }
  })

  it('Should generate a storyboard after torrent import', async function () {
    this.timeout(60000)

    if (areHttpImportTestsDisabled()) return

    // 10s video
    const { video } = await servers[0].imports.importVideo({
      attributes: {
        magnetUri: FIXTURE_URLS.magnet,
        channelId: servers[0].store.channel.id,
        privacy: VideoPrivacy.PUBLIC
      }
    })
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid: video.uuid, tilesCount: 10 })
    }
  })

  it('Should generate a storyboard after a live', async function () {
    this.timeout(240000)

    await servers[0].config.enableLive({ allowReplay: true, transcoding: true, resolutions: 'min' })

    const { live, video } = await servers[0].live.quickCreate({
      saveReplay: true,
      permanentLive: false,
      privacy: VideoPrivacy.PUBLIC
    })

    const ffmpegCommand = sendRTMPStream({ rtmpBaseUrl: live.rtmpUrl, streamKey: live.streamKey })
    await servers[0].live.waitUntilPublished({ videoId: video.id })

    await stopFfmpeg(ffmpegCommand)

    await servers[0].live.waitUntilReplacedByReplay({ videoId: video.id })
    await waitJobs(servers)

    for (const server of servers) {
      await checkStoryboard({ server, uuid: video.uuid })
    }
  })

  it('Should cleanup storyboards on video deletion', async function () {
    this.timeout(60000)

    const { storyboards } = await servers[0].storyboard.list({ id: baseUUID })
    const storyboardName = basename(storyboards[0].storyboardPath)

    const listFiles = () => {
      const storyboardPath = servers[0].getDirectoryPath('storyboards')
      return readdir(storyboardPath)
    }

    {
      const storyboads = await listFiles()
      expect(storyboads).to.include(storyboardName)
    }

    await servers[0].videos.remove({ id: baseUUID })
    await waitJobs(servers)

    {
      const storyboads = await listFiles()
      expect(storyboads).to.not.include(storyboardName)
    }
  })

  after(async function () {
    await cleanupTests(servers)
  })
})