video-imports.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
  2. import { CustomConfig, HttpStatusCode, Video, VideoImportState, VideoPrivacy, VideoResolution, VideoState } from '@peertube/peertube-models'
  3. import { areHttpImportTestsDisabled } from '@peertube/peertube-node-utils'
  4. import {
  5. PeerTubeServer,
  6. cleanupTests, createMultipleServers,
  7. createSingleServer,
  8. doubleFollow,
  9. getServerImportConfig,
  10. setAccessTokensToServers,
  11. setDefaultVideoChannel,
  12. waitJobs
  13. } from '@peertube/peertube-server-commands'
  14. import { DeepPartial } from '@peertube/peertube-typescript-utils'
  15. import { testCaptionFile } from '@tests/shared/captions.js'
  16. import { testImageGeneratedByFFmpeg } from '@tests/shared/checks.js'
  17. import { FIXTURE_URLS } from '@tests/shared/fixture-urls.js'
  18. import { expect } from 'chai'
  19. import { pathExists, remove } from 'fs-extra/esm'
  20. import { readdir } from 'fs/promises'
  21. import { join } from 'path'
  22. async function checkVideosServer1 (server: PeerTubeServer, idHttp: string, idMagnet: string, idTorrent: string) {
  23. const videoHttp = await server.videos.get({ id: idHttp })
  24. expect(videoHttp.name).to.equal('small video - youtube')
  25. expect(videoHttp.category.label).to.equal('News & Politics')
  26. expect(videoHttp.licence.label).to.equal('Attribution')
  27. expect(videoHttp.language.label).to.equal('Unknown')
  28. expect(videoHttp.nsfw).to.be.false
  29. expect(videoHttp.description).to.equal('this is a super description')
  30. expect(videoHttp.tags).to.deep.equal([ 'tag1', 'tag2' ])
  31. expect(videoHttp.files).to.have.lengthOf(1)
  32. const originallyPublishedAt = new Date(videoHttp.originallyPublishedAt)
  33. expect(originallyPublishedAt.getDate()).to.equal(14)
  34. expect(originallyPublishedAt.getMonth()).to.equal(0)
  35. expect(originallyPublishedAt.getFullYear()).to.equal(2019)
  36. const videoMagnet = await server.videos.get({ id: idMagnet })
  37. const videoTorrent = await server.videos.get({ id: idTorrent })
  38. for (const video of [ videoMagnet, videoTorrent ]) {
  39. expect(video.category.label).to.equal('Unknown')
  40. expect(video.licence.label).to.equal('Unknown')
  41. expect(video.language.label).to.equal('Unknown')
  42. expect(video.nsfw).to.be.false
  43. expect(video.description).to.equal('this is a super torrent description')
  44. expect(video.tags).to.deep.equal([ 'tag_torrent1', 'tag_torrent2' ])
  45. expect(video.files).to.have.lengthOf(1)
  46. }
  47. expect(videoTorrent.name).to.contain('你好 世界 720p.mp4')
  48. expect(videoMagnet.name).to.contain('super peertube2 video')
  49. const bodyCaptions = await server.captions.list({ videoId: idHttp })
  50. expect(bodyCaptions.total).to.equal(2)
  51. }
  52. async function checkVideoServer2 (server: PeerTubeServer, id: number | string) {
  53. const video = await server.videos.get({ id })
  54. expect(video.name).to.equal('my super name')
  55. expect(video.category.label).to.equal('Entertainment')
  56. expect(video.licence.label).to.equal('Public Domain Dedication')
  57. expect(video.language.label).to.equal('English')
  58. expect(video.nsfw).to.be.false
  59. expect(video.description).to.equal('my super description')
  60. expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ])
  61. await testImageGeneratedByFFmpeg(server.url, 'custom-thumbnail', video.thumbnailPath)
  62. expect(video.files).to.have.lengthOf(1)
  63. const bodyCaptions = await server.captions.list({ videoId: id })
  64. expect(bodyCaptions.total).to.equal(2)
  65. }
  66. describe('Test video imports', function () {
  67. if (areHttpImportTestsDisabled()) return
  68. function runSuite (mode: 'youtube-dl' | 'yt-dlp') {
  69. describe('Import ' + mode, function () {
  70. let servers: PeerTubeServer[] = []
  71. before(async function () {
  72. this.timeout(60_000)
  73. servers = await createMultipleServers(2, getServerImportConfig(mode))
  74. await setAccessTokensToServers(servers)
  75. await setDefaultVideoChannel(servers)
  76. for (const server of servers) {
  77. await server.config.updateExistingConfig({
  78. newConfig: {
  79. transcoding: {
  80. alwaysTranscodeOriginalResolution: false
  81. }
  82. }
  83. })
  84. }
  85. await doubleFollow(servers[0], servers[1])
  86. })
  87. it('Should import videos on server 1', async function () {
  88. this.timeout(60_000)
  89. const baseAttributes = {
  90. channelId: servers[0].store.channel.id,
  91. privacy: VideoPrivacy.PUBLIC
  92. }
  93. {
  94. const attributes = { ...baseAttributes, targetUrl: FIXTURE_URLS.youtube }
  95. const { video } = await servers[0].videoImports.importVideo({ attributes })
  96. expect(video.name).to.equal('small video - youtube')
  97. {
  98. expect(video.thumbnailPath).to.match(new RegExp(`^/lazy-static/thumbnails/.+.jpg$`))
  99. expect(video.previewPath).to.match(new RegExp(`^/lazy-static/previews/.+.jpg$`))
  100. const suffix = mode === 'yt-dlp'
  101. ? '_yt_dlp'
  102. : ''
  103. await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_thumbnail' + suffix, video.thumbnailPath)
  104. await testImageGeneratedByFFmpeg(servers[0].url, 'video_import_preview' + suffix, video.previewPath)
  105. }
  106. const bodyCaptions = await servers[0].captions.list({ videoId: video.id })
  107. const videoCaptions = bodyCaptions.data
  108. expect(videoCaptions).to.have.lengthOf(2)
  109. {
  110. const enCaption = videoCaptions.find(caption => caption.language.id === 'en')
  111. expect(enCaption).to.exist
  112. expect(enCaption.language.label).to.equal('English')
  113. expect(enCaption.captionPath).to.match(new RegExp(`^/lazy-static/video-captions/.+-en.vtt$`))
  114. const regex = `WEBVTT[ \n]+Kind: captions[ \n]+` +
  115. `(Language: en[ \n]+)?` +
  116. `00:00:01.600 --> 00:00:04.200( position:\\d+% line:\\d+%)?[ \n]+English \\(US\\)[ \n]+` +
  117. `00:00:05.900 --> 00:00:07.999( position:\\d+% line:\\d+%)?[ \n]+This is a subtitle in American English[ \n]+` +
  118. `00:00:10.000 --> 00:00:14.000( position:\\d+% line:\\d+%)?[ \n]+Adding subtitles is very easy to do`
  119. await testCaptionFile(servers[0].url, enCaption.captionPath, new RegExp(regex))
  120. }
  121. {
  122. const frCaption = videoCaptions.find(caption => caption.language.id === 'fr')
  123. expect(frCaption).to.exist
  124. expect(frCaption.language.label).to.equal('French')
  125. expect(frCaption.captionPath).to.match(new RegExp(`^/lazy-static/video-captions/.+-fr.vtt`))
  126. const regex = `WEBVTT[ \n]+Kind: captions[ \n]+` +
  127. `(Language: fr[ \n]+)?` +
  128. `00:00:01.600 --> 00:00:04.200( position:\\d+% line:\\d+%)?[ \n]+Français \\(FR\\)[ \n]+` +
  129. `00:00:05.900 --> 00:00:07.999( position:\\d+% line:\\d+%)?[ \n]+C'est un sous-titre français[ \n]+` +
  130. `00:00:10.000 --> 00:00:14.000( position:\\d+% line:\\d+%)?[ \n]+Ajouter un sous-titre est vraiment facile`
  131. await testCaptionFile(servers[0].url, frCaption.captionPath, new RegExp(regex))
  132. }
  133. }
  134. {
  135. const attributes = {
  136. ...baseAttributes,
  137. magnetUri: FIXTURE_URLS.magnet,
  138. description: 'this is a super torrent description',
  139. tags: [ 'tag_torrent1', 'tag_torrent2' ]
  140. }
  141. const { video } = await servers[0].videoImports.importVideo({ attributes })
  142. expect(video.name).to.equal('super peertube2 video')
  143. }
  144. {
  145. const attributes = {
  146. ...baseAttributes,
  147. torrentfile: 'video-720p.torrent' as any,
  148. description: 'this is a super torrent description',
  149. tags: [ 'tag_torrent1', 'tag_torrent2' ]
  150. }
  151. const { video } = await servers[0].videoImports.importVideo({ attributes })
  152. expect(video.name).to.equal('你好 世界 720p.mp4')
  153. }
  154. })
  155. it('Should list the videos to import in my videos on server 1', async function () {
  156. const { total, data } = await servers[0].videos.listMyVideos({ sort: 'createdAt' })
  157. expect(total).to.equal(3)
  158. expect(data).to.have.lengthOf(3)
  159. expect(data[0].name).to.equal('small video - youtube')
  160. expect(data[1].name).to.equal('super peertube2 video')
  161. expect(data[2].name).to.equal('你好 世界 720p.mp4')
  162. })
  163. it('Should list the videos to import in my imports on server 1', async function () {
  164. const { total, data: videoImports } = await servers[0].videoImports.getMyVideoImports({ sort: '-createdAt' })
  165. expect(total).to.equal(3)
  166. expect(videoImports).to.have.lengthOf(3)
  167. expect(videoImports[2].targetUrl).to.equal(FIXTURE_URLS.youtube)
  168. expect(videoImports[2].magnetUri).to.be.null
  169. expect(videoImports[2].torrentName).to.be.null
  170. expect(videoImports[2].video.name).to.equal('small video - youtube')
  171. expect(videoImports[1].targetUrl).to.be.null
  172. expect(videoImports[1].magnetUri).to.equal(FIXTURE_URLS.magnet)
  173. expect(videoImports[1].torrentName).to.be.null
  174. expect(videoImports[1].video.name).to.equal('super peertube2 video')
  175. expect(videoImports[0].targetUrl).to.be.null
  176. expect(videoImports[0].magnetUri).to.be.null
  177. expect(videoImports[0].torrentName).to.equal('video-720p.torrent')
  178. expect(videoImports[0].video.name).to.equal('你好 世界 720p.mp4')
  179. })
  180. it('Should filter my imports on target URL', async function () {
  181. const { total, data: videoImports } = await servers[0].videoImports.getMyVideoImports({ targetUrl: FIXTURE_URLS.youtube })
  182. expect(total).to.equal(1)
  183. expect(videoImports).to.have.lengthOf(1)
  184. expect(videoImports[0].targetUrl).to.equal(FIXTURE_URLS.youtube)
  185. })
  186. it('Should search in my imports', async function () {
  187. {
  188. const { total, data } = await servers[0].videoImports.getMyVideoImports({ search: 'peertube2' })
  189. expect(total).to.equal(1)
  190. expect(data).to.have.lengthOf(1)
  191. expect(data[0].magnetUri).to.equal(FIXTURE_URLS.magnet)
  192. expect(data[0].video.name).to.equal('super peertube2 video')
  193. }
  194. {
  195. const { total, data } = await servers[0].videoImports.getMyVideoImports({ search: FIXTURE_URLS.magnet })
  196. expect(total).to.equal(1)
  197. expect(data).to.have.lengthOf(1)
  198. expect(data[0].magnetUri).to.equal(FIXTURE_URLS.magnet)
  199. expect(data[0].video.name).to.equal('super peertube2 video')
  200. }
  201. })
  202. it('Should have the video listed on the two instances', async function () {
  203. this.timeout(120_000)
  204. await waitJobs(servers)
  205. for (const server of servers) {
  206. const { total, data } = await server.videos.list()
  207. expect(total).to.equal(3)
  208. expect(data).to.have.lengthOf(3)
  209. const [ videoHttp, videoMagnet, videoTorrent ] = data
  210. await checkVideosServer1(server, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid)
  211. }
  212. })
  213. it('Should import a video on server 2 with some fields', async function () {
  214. this.timeout(60_000)
  215. const { video } = await servers[1].videoImports.importVideo({
  216. attributes: {
  217. targetUrl: FIXTURE_URLS.youtube,
  218. channelId: servers[1].store.channel.id,
  219. privacy: VideoPrivacy.PUBLIC,
  220. category: 10,
  221. licence: 7,
  222. language: 'en',
  223. name: 'my super name',
  224. description: 'my super description',
  225. tags: [ 'supertag1', 'supertag2' ],
  226. thumbnailfile: 'custom-thumbnail.jpg'
  227. }
  228. })
  229. expect(video.name).to.equal('my super name')
  230. })
  231. it('Should have the videos listed on the two instances', async function () {
  232. this.timeout(120_000)
  233. await waitJobs(servers)
  234. for (const server of servers) {
  235. const { total, data } = await server.videos.list()
  236. expect(total).to.equal(4)
  237. expect(data).to.have.lengthOf(4)
  238. await checkVideoServer2(server, data[0].uuid)
  239. const [ , videoHttp, videoMagnet, videoTorrent ] = data
  240. await checkVideosServer1(server, videoHttp.uuid, videoMagnet.uuid, videoTorrent.uuid)
  241. }
  242. })
  243. it('Should import a video that will be transcoded', async function () {
  244. this.timeout(240_000)
  245. const attributes = {
  246. name: 'transcoded video',
  247. magnetUri: FIXTURE_URLS.magnet,
  248. channelId: servers[1].store.channel.id,
  249. privacy: VideoPrivacy.PUBLIC
  250. }
  251. const { video } = await servers[1].videoImports.importVideo({ attributes })
  252. const videoUUID = video.uuid
  253. await waitJobs(servers)
  254. for (const server of servers) {
  255. const video = await server.videos.get({ id: videoUUID })
  256. expect(video.name).to.equal('transcoded video')
  257. expect(video.files).to.have.lengthOf(4)
  258. }
  259. })
  260. it('Should import no HDR version on a HDR video', async function () {
  261. this.timeout(300_000)
  262. const config: DeepPartial<CustomConfig> = {
  263. transcoding: {
  264. enabled: true,
  265. resolutions: {
  266. '0p': false,
  267. '144p': true,
  268. '240p': true,
  269. '360p': false,
  270. '480p': false,
  271. '720p': false,
  272. '1080p': false, // the resulting resolution shouldn't be higher than this, and not vp9.2/av01
  273. '1440p': false,
  274. '2160p': false
  275. },
  276. webVideos: { enabled: true },
  277. hls: { enabled: false }
  278. }
  279. }
  280. await servers[0].config.updateExistingConfig({ newConfig: config })
  281. const attributes = {
  282. name: 'hdr video',
  283. targetUrl: FIXTURE_URLS.youtubeHDR,
  284. channelId: servers[0].store.channel.id,
  285. privacy: VideoPrivacy.PUBLIC
  286. }
  287. const { video: videoImported } = await servers[0].videoImports.importVideo({ attributes })
  288. const videoUUID = videoImported.uuid
  289. await waitJobs(servers)
  290. // test resolution
  291. const video = await servers[0].videos.get({ id: videoUUID })
  292. expect(video.name).to.equal('hdr video')
  293. const maxResolution = Math.max.apply(Math, video.files.map(function (o) { return o.resolution.id }))
  294. expect(maxResolution, 'expected max resolution not met').to.equals(VideoResolution.H_240P)
  295. })
  296. it('Should not import resolution higher than enabled transcoding resolution', async function () {
  297. this.timeout(300_000)
  298. const config: DeepPartial<CustomConfig> = {
  299. transcoding: {
  300. enabled: true,
  301. resolutions: {
  302. '0p': false,
  303. '144p': true,
  304. '240p': false,
  305. '360p': false,
  306. '480p': false,
  307. '720p': false,
  308. '1080p': false,
  309. '1440p': false,
  310. '2160p': false
  311. },
  312. alwaysTranscodeOriginalResolution: false
  313. }
  314. }
  315. await servers[0].config.updateExistingConfig({ newConfig: config })
  316. const attributes = {
  317. name: 'small resolution video',
  318. targetUrl: FIXTURE_URLS.youtube,
  319. channelId: servers[0].store.channel.id,
  320. privacy: VideoPrivacy.PUBLIC
  321. }
  322. const { video: videoImported } = await servers[0].videoImports.importVideo({ attributes })
  323. const videoUUID = videoImported.uuid
  324. await waitJobs(servers)
  325. // test resolution
  326. const video = await servers[0].videos.get({ id: videoUUID })
  327. expect(video.name).to.equal('small resolution video')
  328. expect(video.files).to.have.lengthOf(1)
  329. expect(video.files[0].resolution.id).to.equal(144)
  330. })
  331. it('Should import resolution higher than enabled transcoding resolution', async function () {
  332. this.timeout(300_000)
  333. const config: DeepPartial<CustomConfig> = {
  334. transcoding: {
  335. alwaysTranscodeOriginalResolution: true
  336. }
  337. }
  338. await servers[0].config.updateExistingConfig({ newConfig: config })
  339. const attributes = {
  340. name: 'bigger resolution video',
  341. targetUrl: FIXTURE_URLS.youtube,
  342. channelId: servers[0].store.channel.id,
  343. privacy: VideoPrivacy.PUBLIC
  344. }
  345. const { video: videoImported } = await servers[0].videoImports.importVideo({ attributes })
  346. const videoUUID = videoImported.uuid
  347. await waitJobs(servers)
  348. // test resolution
  349. const video = await servers[0].videos.get({ id: videoUUID })
  350. expect(video.name).to.equal('bigger resolution video')
  351. expect(video.files).to.have.lengthOf(2)
  352. expect(video.files.find(f => f.resolution.id === 240)).to.exist
  353. expect(video.files.find(f => f.resolution.id === 144)).to.exist
  354. })
  355. it('Should import a peertube video', async function () {
  356. this.timeout(120_000)
  357. const toTest = [ FIXTURE_URLS.peertube_long ]
  358. // TODO: include peertube_short when https://github.com/ytdl-org/youtube-dl/pull/29475 is merged
  359. if (mode === 'yt-dlp') {
  360. toTest.push(FIXTURE_URLS.peertube_short)
  361. }
  362. for (const targetUrl of toTest) {
  363. await servers[0].config.disableTranscoding()
  364. const attributes = {
  365. targetUrl,
  366. channelId: servers[0].store.channel.id,
  367. privacy: VideoPrivacy.PUBLIC
  368. }
  369. const { video } = await servers[0].videoImports.importVideo({ attributes })
  370. const videoUUID = video.uuid
  371. await waitJobs(servers)
  372. for (const server of servers) {
  373. const video = await server.videos.get({ id: videoUUID })
  374. expect(video.name).to.equal('E2E tests')
  375. const { data: captions } = await server.captions.list({ videoId: videoUUID })
  376. expect(captions).to.have.lengthOf(1)
  377. expect(captions[0].language.id).to.equal('fr')
  378. const str = `WEBVTT FILE\r?\n\r?\n` +
  379. `1\r?\n` +
  380. `00:00:04.000 --> 00:00:09.000\r?\n` +
  381. `January 1, 1994. The North American`
  382. await testCaptionFile(server.url, captions[0].captionPath, new RegExp(str))
  383. }
  384. }
  385. })
  386. after(async function () {
  387. await cleanupTests(servers)
  388. })
  389. })
  390. }
  391. // FIXME: youtube-dl seems broken
  392. // runSuite('youtube-dl')
  393. runSuite('yt-dlp')
  394. describe('Delete/cancel an import', function () {
  395. let server: PeerTubeServer
  396. let finishedImportId: number
  397. let finishedVideo: Video
  398. let pendingImportId: number
  399. async function importVideo (name: string) {
  400. const attributes = { name, channelId: server.store.channel.id, targetUrl: FIXTURE_URLS.goodVideo }
  401. const res = await server.videoImports.importVideo({ attributes })
  402. return res.id
  403. }
  404. before(async function () {
  405. this.timeout(120_000)
  406. server = await createSingleServer(1)
  407. await setAccessTokensToServers([ server ])
  408. await setDefaultVideoChannel([ server ])
  409. finishedImportId = await importVideo('finished')
  410. await waitJobs([ server ])
  411. await server.jobs.pauseJobQueue()
  412. pendingImportId = await importVideo('pending')
  413. const { data } = await server.videoImports.getMyVideoImports()
  414. expect(data).to.have.lengthOf(2)
  415. finishedVideo = data.find(i => i.id === finishedImportId).video
  416. })
  417. it('Should delete a video import', async function () {
  418. await server.videoImports.delete({ importId: finishedImportId })
  419. const { data } = await server.videoImports.getMyVideoImports()
  420. expect(data).to.have.lengthOf(1)
  421. expect(data[0].id).to.equal(pendingImportId)
  422. expect(data[0].state.id).to.equal(VideoImportState.PENDING)
  423. })
  424. it('Should not have deleted the associated video', async function () {
  425. const video = await server.videos.get({ id: finishedVideo.id, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 })
  426. expect(video.name).to.equal('finished')
  427. expect(video.state.id).to.equal(VideoState.PUBLISHED)
  428. })
  429. it('Should cancel a video import', async function () {
  430. await server.videoImports.cancel({ importId: pendingImportId })
  431. const { data } = await server.videoImports.getMyVideoImports()
  432. expect(data).to.have.lengthOf(1)
  433. expect(data[0].id).to.equal(pendingImportId)
  434. expect(data[0].state.id).to.equal(VideoImportState.CANCELLED)
  435. })
  436. it('Should not have processed the cancelled video import', async function () {
  437. this.timeout(60_000)
  438. await server.jobs.resumeJobQueue()
  439. await waitJobs([ server ])
  440. const { data } = await server.videoImports.getMyVideoImports()
  441. expect(data).to.have.lengthOf(1)
  442. expect(data[0].id).to.equal(pendingImportId)
  443. expect(data[0].state.id).to.equal(VideoImportState.CANCELLED)
  444. expect(data[0].video.state.id).to.equal(VideoState.TO_IMPORT)
  445. })
  446. it('Should delete the cancelled video import', async function () {
  447. await server.videoImports.delete({ importId: pendingImportId })
  448. const { data } = await server.videoImports.getMyVideoImports()
  449. expect(data).to.have.lengthOf(0)
  450. })
  451. after(async function () {
  452. await cleanupTests([ server ])
  453. })
  454. })
  455. describe('Auto update', function () {
  456. let server: PeerTubeServer
  457. function quickPeerTubeImport () {
  458. const attributes = {
  459. targetUrl: FIXTURE_URLS.peertube_long,
  460. channelId: server.store.channel.id,
  461. privacy: VideoPrivacy.PUBLIC
  462. }
  463. return server.videoImports.importVideo({ attributes })
  464. }
  465. async function testBinaryUpdate (releaseUrl: string, releaseName: string) {
  466. await remove(join(server.servers.buildDirectory('bin'), releaseName))
  467. await server.kill()
  468. await server.run({
  469. import: {
  470. videos: {
  471. http: {
  472. youtube_dl_release: {
  473. url: releaseUrl,
  474. name: releaseName
  475. }
  476. }
  477. }
  478. }
  479. })
  480. await quickPeerTubeImport()
  481. const base = server.servers.buildDirectory('bin')
  482. const content = await readdir(base)
  483. const binaryPath = join(base, releaseName)
  484. expect(await pathExists(binaryPath), `${binaryPath} does not exist in ${base} (${content.join(', ')})`).to.be.true
  485. }
  486. before(async function () {
  487. this.timeout(30_000)
  488. // Run servers
  489. server = await createSingleServer(1)
  490. await setAccessTokensToServers([ server ])
  491. await setDefaultVideoChannel([ server ])
  492. })
  493. it('Should update youtube-dl from github URL', async function () {
  494. this.timeout(120_000)
  495. await testBinaryUpdate('https://api.github.com/repos/ytdl-org/youtube-dl/releases', 'youtube-dl')
  496. })
  497. // FIXME: official instance is broken
  498. // it('Should update youtube-dl from raw URL', async function () {
  499. // this.timeout(120_000)
  500. // await testBinaryUpdate('https://yt-dl.org/downloads/latest/youtube-dl', 'youtube-dl')
  501. // })
  502. it('Should update youtube-dl from youtube-dl fork', async function () {
  503. this.timeout(120_000)
  504. await testBinaryUpdate('https://api.github.com/repos/yt-dlp/yt-dlp/releases', 'yt-dlp')
  505. })
  506. after(async function () {
  507. await cleanupTests([ server ])
  508. })
  509. })
  510. })