From 22e9d9a1fe52b4358bdebffe99d5eafb17a93e5d Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 31 Jul 2024 09:26:54 +0200 Subject: [PATCH] Fix updating hls infohash on privacy update --- .../video-static-file-privacy.ts | 8 +-- .../tests/src/api/object-storage/videos.ts | 25 ++++------ .../tests/src/shared/streaming-playlists.ts | 49 +++++++++++-------- server/core/lib/video-jobs.ts | 6 +++ 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/packages/tests/src/api/object-storage/video-static-file-privacy.ts b/packages/tests/src/api/object-storage/video-static-file-privacy.ts index d3105ffbd..f5e38de5e 100644 --- a/packages/tests/src/api/object-storage/video-static-file-privacy.ts +++ b/packages/tests/src/api/object-storage/video-static-file-privacy.ts @@ -1,7 +1,5 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { basename } from 'path' import { getAllFiles, getHLS } from '@peertube/peertube-core-utils' import { HttpStatusCode, LiveVideo, VideoDetails, VideoPrivacy } from '@peertube/peertube-models' import { areScalewayObjectStorageTestsDisabled } from '@peertube/peertube-node-utils' @@ -20,7 +18,9 @@ import { } from '@peertube/peertube-server-commands' import { expectStartWith } from '@tests/shared/checks.js' import { SQLCommand } from '@tests/shared/sql-command.js' -import { checkVideoFileTokenReinjection } from '@tests/shared/streaming-playlists.js' +import { checkPlaylistInfohash, checkVideoFileTokenReinjection } from '@tests/shared/streaming-playlists.js' +import { expect } from 'chai' +import { basename } from 'path' function extractFilenameFromUrl (url: string) { const parts = basename(url).split(':') @@ -74,6 +74,8 @@ describe('Object storage for video static file privacy', function () { await makeRawRequest({ url: file.fileUrl, token: server.accessToken, expectedStatus: HttpStatusCode.OK_200 }) } + + await checkPlaylistInfohash({ video, files: hls.files, sqlCommand }) } } diff --git a/packages/tests/src/api/object-storage/videos.ts b/packages/tests/src/api/object-storage/videos.ts index 66bca5cc8..bbfaab3eb 100644 --- a/packages/tests/src/api/object-storage/videos.ts +++ b/packages/tests/src/api/object-storage/videos.ts @@ -1,11 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import bytes from 'bytes' -import { expect } from 'chai' -import { stat } from 'fs/promises' -import merge from 'lodash-es/merge.js' import { HttpStatusCode, VideoDetails } from '@peertube/peertube-models' -import { areMockObjectStorageTestsDisabled, sha1 } from '@peertube/peertube-node-utils' +import { areMockObjectStorageTestsDisabled } from '@peertube/peertube-node-utils' import { cleanupTests, createMultipleServers, @@ -18,12 +14,17 @@ import { setAccessTokensToServers, waitJobs } from '@peertube/peertube-server-commands' -import { expectStartWith, expectLogDoesNotContain } from '@tests/shared/checks.js' +import { expectLogDoesNotContain, expectStartWith } from '@tests/shared/checks.js' import { checkTmpIsEmpty } from '@tests/shared/directories.js' import { generateHighBitrateVideo } from '@tests/shared/generate.js' import { MockObjectStorageProxy } from '@tests/shared/mock-servers/mock-object-storage.js' import { SQLCommand } from '@tests/shared/sql-command.js' +import { checkPlaylistInfohash } from '@tests/shared/streaming-playlists.js' import { checkWebTorrentWorks } from '@tests/shared/webtorrent.js' +import bytes from 'bytes' +import { expect } from 'chai' +import { stat } from 'fs/promises' +import merge from 'lodash-es/merge.js' async function checkFiles (options: { server: PeerTubeServer @@ -91,7 +92,6 @@ async function checkFiles (options: { const resSha = await makeRawRequest({ url: hls.segmentsSha256Url, expectedStatus: HttpStatusCode.OK_200 }) expect(JSON.stringify(resSha.body)).to.not.throw - let i = 0 for (const file of hls.files) { expectStartWith(file.fileUrl, start) @@ -100,15 +100,10 @@ async function checkFiles (options: { expectStartWith(location, start) await makeRawRequest({ url: location, expectedStatus: HttpStatusCode.OK_200 }) + } - if (originServer.internalServerNumber === server.internalServerNumber) { - const infohash = sha1(`${2 + hls.playlistUrl}+V${i}`) - const dbInfohashes = await originSQLCommand.getPlaylistInfohash(hls.id) - - expect(dbInfohashes).to.include(infohash) - } - - i++ + if (originServer.internalServerNumber === server.internalServerNumber) { + await checkPlaylistInfohash({ video, files: hls.files, sqlCommand: originSQLCommand }) } } diff --git a/packages/tests/src/shared/streaming-playlists.ts b/packages/tests/src/shared/streaming-playlists.ts index b187ba47c..87c318f8a 100644 --- a/packages/tests/src/shared/streaming-playlists.ts +++ b/packages/tests/src/shared/streaming-playlists.ts @@ -1,22 +1,24 @@ /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ -import { expect } from 'chai' -import { basename, dirname, join } from 'path' -import { removeFragmentedMP4Ext, uuidRegex } from '@peertube/peertube-core-utils' +import { getHLS, removeFragmentedMP4Ext, uuidRegex } from '@peertube/peertube-core-utils' import { HttpStatusCode, + VideoDetails, VideoPrivacy, VideoResolution, VideoStreamingPlaylist, VideoStreamingPlaylistType } from '@peertube/peertube-models' -import { sha256 } from '@peertube/peertube-node-utils' +import { sha1, sha256 } from '@peertube/peertube-node-utils' import { makeRawRequest, PeerTubeServer } from '@peertube/peertube-server-commands' +import { expect } from 'chai' +import { basename, dirname, join } from 'path' import { expectStartWith } from './checks.js' +import { SQLCommand } from './sql-command.js' import { hlsInfohashExist } from './tracker.js' import { checkWebTorrentWorks } from './webtorrent.js' -async function checkSegmentHash (options: { +export async function checkSegmentHash (options: { server: PeerTubeServer baseUrlPlaylist: string baseUrlSegment: string @@ -49,9 +51,7 @@ async function checkSegmentHash (options: { expect(sha256(segmentBody)).to.equal(shaBody[videoName][range], `Invalid sha256 result for ${videoName} range ${range}`) } -// --------------------------------------------------------------------------- - -async function checkLiveSegmentHash (options: { +export async function checkLiveSegmentHash (options: { server: PeerTubeServer baseUrlSegment: string videoUUID: string @@ -68,9 +68,25 @@ async function checkLiveSegmentHash (options: { expect(sha256(segmentBody)).to.equal(shaBody[segmentName]) } +export async function checkPlaylistInfohash (options: { + video: VideoDetails + sqlCommand: SQLCommand + files: unknown[] +}) { + const { sqlCommand, video, files } = options + const hls = getHLS(video) + + for (let i = 0; i < files.length; i++) { + const infohash = sha1(`${2 + hls.playlistUrl}+V${i}`) + const dbInfohashes = await sqlCommand.getPlaylistInfohash(hls.id) + + expect(dbInfohashes).to.include(infohash) + } +} + // --------------------------------------------------------------------------- -async function checkResolutionsInMasterPlaylist (options: { +export async function checkResolutionsInMasterPlaylist (options: { server: PeerTubeServer playlistUrl: string resolutions: number[] @@ -98,7 +114,7 @@ async function checkResolutionsInMasterPlaylist (options: { expect(playlistsLength).to.have.lengthOf(resolutions.length) } -async function completeCheckHlsPlaylist (options: { +export async function completeCheckHlsPlaylist (options: { servers: PeerTubeServer[] videoUUID: string hlsOnly: boolean @@ -255,7 +271,7 @@ async function completeCheckHlsPlaylist (options: { } } -async function checkVideoFileTokenReinjection (options: { +export async function checkVideoFileTokenReinjection (options: { server: PeerTubeServer videoUUID: string videoFileToken: string @@ -295,16 +311,7 @@ async function checkVideoFileTokenReinjection (options: { } } -function extractResolutionPlaylistUrls (masterPath: string, masterContent: string) { +export function extractResolutionPlaylistUrls (masterPath: string, masterContent: string) { return masterContent.match(/^([^.]+\.m3u8.*)/mg) .map(filename => join(dirname(masterPath), filename)) } - -export { - checkSegmentHash, - checkLiveSegmentHash, - checkResolutionsInMasterPlaylist, - completeCheckHlsPlaylist, - extractResolutionPlaylistUrls, - checkVideoFileTokenReinjection -} diff --git a/server/core/lib/video-jobs.ts b/server/core/lib/video-jobs.ts index 411a9aead..9af0f5c99 100644 --- a/server/core/lib/video-jobs.ts +++ b/server/core/lib/video-jobs.ts @@ -125,6 +125,12 @@ export async function addVideoJobsAfterUpdate (options: { const jobs: CreateJobArgument[] = [] const filePathChanged = await moveFilesIfPrivacyChanged(video, oldPrivacy) + const hls = video.getHLSPlaylist() + + if (filePathChanged && hls) { + hls.assignP2PMediaLoaderInfoHashes(video, hls.VideoFiles) + await hls.save() + } if (!video.isLive && (nameChanged || filePathChanged)) { for (const file of (video.VideoFiles || [])) {