doubleFollow,
flushAndRunMultipleServers,
getMyVideosWithFilter,
- getPlaylist,
getVideo,
getVideosList,
getVideosWithFilters,
// Only finite files are displayed
expect(hlsPlaylist.files).to.have.lengthOf(0)
- await checkResolutionsInMasterPlaylist(hlsPlaylist.playlistUrl, resolutions)
+ await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions })
for (let i = 0; i < resolutions.length; i++) {
const segmentNum = 3
const segmentName = `${i}-00000${segmentNum}.ts`
await commands[0].waitUntilSegmentGeneration({ videoUUID: video.uuid, resolution: i, segment: segmentNum })
- const res = await getPlaylist(`${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8`)
- const subPlaylist = res.text
+ const subPlaylist = await servers[0].streamingPlaylistsCommand.get({
+ url: `${servers[0].url}/static/streaming-playlists/hls/${video.uuid}/${i}.m3u8`
+ })
expect(subPlaylist).to.contain(segmentName)
const baseUrlAndPath = servers[0].url + '/static/streaming-playlists/hls'
- await checkLiveSegmentHash(baseUrlAndPath, video.uuid, segmentName, hlsPlaylist)
+ await checkLiveSegmentHash({
+ server,
+ baseUrlSegment: baseUrlAndPath,
+ videoUUID: video.uuid,
+ segmentName,
+ hlsPlaylist
+ })
}
}
}
const hlsPlaylist = (res.body as VideoDetails).streamingPlaylists[0]
for (const resolution of [ 240, 360, 480, 720 ]) {
- await checkSegmentHash(baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist)
+ await checkSegmentHash({ server: servers[1], baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist })
}
const directories = [
cleanupTests,
doubleFollow,
flushAndRunMultipleServers,
- getPlaylist,
getVideo,
makeRawRequest,
removeVideo,
}
{
- await checkResolutionsInMasterPlaylist(hlsPlaylist.playlistUrl, resolutions)
+ await checkResolutionsInMasterPlaylist({ server, playlistUrl: hlsPlaylist.playlistUrl, resolutions })
- const res = await getPlaylist(hlsPlaylist.playlistUrl)
- const masterPlaylist = res.text
+ const masterPlaylist = await server.streamingPlaylistsCommand.get({ url: hlsPlaylist.playlistUrl })
for (const resolution of resolutions) {
expect(masterPlaylist).to.contain(`${resolution}.m3u8`)
{
for (const resolution of resolutions) {
- const res = await getPlaylist(`${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`)
+ const subPlaylist = await server.streamingPlaylistsCommand.get({
+ url: `${baseUrl}/static/streaming-playlists/hls/${videoUUID}/${resolution}.m3u8`
+ })
- const subPlaylist = res.text
expect(subPlaylist).to.contain(`${videoUUID}-${resolution}-fragmented.mp4`)
}
}
const baseUrlAndPath = baseUrl + '/static/streaming-playlists/hls'
for (const resolution of resolutions) {
- await checkSegmentHash(baseUrlAndPath, baseUrlAndPath, videoUUID, resolution, hlsPlaylist)
+ await checkSegmentHash({
+ server,
+ baseUrlPlaylist: baseUrlAndPath,
+ baseUrlSegment: baseUrlAndPath,
+ videoUUID,
+ resolution,
+ hlsPlaylist
+ })
}
}
}
ImportsCommand,
LiveCommand,
PlaylistsCommand,
- ServicesCommand
+ ServicesCommand,
+ StreamingPlaylistsCommand
} from '../videos'
import { ConfigCommand } from './config-command'
import { ContactFormCommand } from './contact-form-command'
playlistsCommand?: PlaylistsCommand
historyCommand?: HistoryCommand
importsCommand?: ImportsCommand
+ streamingPlaylistsCommand?: StreamingPlaylistsCommand
}
function parallelTests () {
server.playlistsCommand = new PlaylistsCommand(server)
server.historyCommand = new HistoryCommand(server)
server.importsCommand = new ImportsCommand(server)
+ server.streamingPlaylistsCommand = new StreamingPlaylistsCommand(server)
res(server)
})
}
interface InternalCommonCommandOptions extends OverrideCommandOptions {
+ // Default to server.url
+ url?: string
+
path: string
// If we automatically send the server token if the token is not provided
implicitToken: boolean
contentType?: string
accept?: string
redirects?: number
+ range?: string
}
abstract class AbstractCommand {
return unwrapText(this.getRequest(options))
}
+ protected getRawRequest (options: Omit<InternalGetCommandOptions, 'path'>) {
+ const { url, range } = options
+ const { host, protocol, pathname } = new URL(url)
+
+ return this.getRequest({
+ ...options,
+
+ token: this.buildCommonRequestToken(options),
+ defaultExpectedStatus: this.buildStatusCodeExpected(options),
+
+ url: `${protocol}//${host}`,
+ path: pathname,
+ range
+ })
+ }
+
protected getRequest (options: InternalGetCommandOptions) {
const { redirects, query, contentType, accept } = options
}
private buildCommonRequestOptions (options: InternalCommonCommandOptions) {
- const { token, expectedStatus, defaultExpectedStatus, path } = options
+ const { path } = options
+
+ return {
+ url: this.server.url,
+ path,
+
+ token: this.buildCommonRequestToken(options),
+ statusCodeExpected: this.buildStatusCodeExpected(options)
+ }
+ }
+
+ private buildCommonRequestToken (options: Pick<InternalCommonCommandOptions, 'token' | 'implicitToken'>) {
+ const { token } = options
const fallbackToken = options.implicitToken
? this.server.accessToken
: undefined
- return {
- url: this.server.url,
- path,
+ return token !== undefined ? token : fallbackToken
+ }
- token: token !== undefined ? token : fallbackToken,
+ private buildStatusCodeExpected (options: Pick<InternalCommonCommandOptions, 'expectedStatus' | 'defaultExpectedStatus'>) {
+ const { expectedStatus, defaultExpectedStatus } = options
- statusCodeExpected: expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus
- }
+ return expectedStatus ?? this.expectedStatus ?? defaultExpectedStatus
}
}
export * from './playlists-command'
export * from './playlists'
export * from './services-command'
+export * from './streaming-playlists-command'
+export * from './streaming-playlists'
export * from './video-channels'
export * from './video-comments'
-export * from './video-streaming-playlists'
export * from './videos'
--- /dev/null
+
+import { HttpStatusCode } from '../../core-utils/miscs/http-error-codes'
+import { unwrapBody, unwrapText } from '../requests'
+import { AbstractCommand, OverrideCommandOptions } from '../shared'
+
+export class StreamingPlaylistsCommand extends AbstractCommand {
+
+ get (options: OverrideCommandOptions & {
+ url: string
+ }) {
+ return unwrapText(this.getRawRequest({
+ ...options,
+
+ url: options.url,
+ implicitToken: false,
+ defaultExpectedStatus: HttpStatusCode.OK_200
+ }))
+ }
+
+ getSegment (options: OverrideCommandOptions & {
+ url: string
+ range?: string
+ }) {
+ return unwrapText(this.getRawRequest({
+ ...options,
+
+ url: options.url,
+ range: options.range,
+ implicitToken: false,
+ defaultExpectedStatus: HttpStatusCode.OK_200,
+ }))
+ }
+
+ getSegmentSha256 (options: OverrideCommandOptions & {
+ url: string
+ }) {
+ return unwrapBody<{ [ id: string ]: string }>(this.getRawRequest({
+ ...options,
+
+ url: options.url,
+ implicitToken: false,
+ defaultExpectedStatus: HttpStatusCode.OK_200
+ }))
+ }
+}
--- /dev/null
+import { expect } from 'chai'
+import { sha256 } from '@server/helpers/core-utils'
+import { HttpStatusCode } from '@shared/core-utils'
+import { VideoStreamingPlaylist } from '@shared/models'
+import { ServerInfo } from '../server'
+
+async function checkSegmentHash (options: {
+ server: ServerInfo
+ baseUrlPlaylist: string
+ baseUrlSegment: string
+ videoUUID: string
+ resolution: number
+ hlsPlaylist: VideoStreamingPlaylist
+}) {
+ const { server, baseUrlPlaylist, baseUrlSegment, videoUUID, resolution, hlsPlaylist } = options
+ const command = server.streamingPlaylistsCommand
+
+ const playlist = await command.get({ url: `${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8` })
+
+ const videoName = `${videoUUID}-${resolution}-fragmented.mp4`
+
+ const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
+
+ const length = parseInt(matches[1], 10)
+ const offset = parseInt(matches[2], 10)
+ const range = `${offset}-${offset + length - 1}`
+
+ const segmentBody = await command.getSegment({
+ url: `${baseUrlSegment}/${videoUUID}/${videoName}`,
+ expectedStatus: HttpStatusCode.PARTIAL_CONTENT_206,
+ range: `bytes=${range}`
+ })
+
+ const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url })
+ expect(sha256(segmentBody)).to.equal(shaBody[videoName][range])
+}
+
+async function checkLiveSegmentHash (options: {
+ server: ServerInfo
+ baseUrlSegment: string
+ videoUUID: string
+ segmentName: string
+ hlsPlaylist: VideoStreamingPlaylist
+}) {
+ const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options
+ const command = server.streamingPlaylistsCommand
+
+ const segmentBody = await command.getSegment({ url: `${baseUrlSegment}/${videoUUID}/${segmentName}` })
+ const shaBody = await command.getSegmentSha256({ url: hlsPlaylist.segmentsSha256Url })
+
+ expect(sha256(segmentBody)).to.equal(shaBody[segmentName])
+}
+
+async function checkResolutionsInMasterPlaylist (options: {
+ server: ServerInfo
+ playlistUrl: string
+ resolutions: number[]
+}) {
+ const { server, playlistUrl, resolutions } = options
+
+ const masterPlaylist = await server.streamingPlaylistsCommand.get({ url: playlistUrl })
+
+ for (const resolution of resolutions) {
+ const reg = new RegExp(
+ '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"'
+ )
+
+ expect(masterPlaylist).to.match(reg)
+ }
+}
+
+export {
+ checkSegmentHash,
+ checkLiveSegmentHash,
+ checkResolutionsInMasterPlaylist
+}
+++ /dev/null
-import { makeRawRequest } from '../requests/requests'
-import { sha256 } from '../../../server/helpers/core-utils'
-import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model'
-import { expect } from 'chai'
-import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes'
-
-function getPlaylist (url: string, statusCodeExpected = HttpStatusCode.OK_200) {
- return makeRawRequest(url, statusCodeExpected)
-}
-
-function getSegment (url: string, statusCodeExpected = HttpStatusCode.OK_200, range?: string) {
- return makeRawRequest(url, statusCodeExpected, range)
-}
-
-function getSegmentSha256 (url: string, statusCodeExpected = HttpStatusCode.OK_200) {
- return makeRawRequest(url, statusCodeExpected)
-}
-
-async function checkSegmentHash (
- baseUrlPlaylist: string,
- baseUrlSegment: string,
- videoUUID: string,
- resolution: number,
- hlsPlaylist: VideoStreamingPlaylist
-) {
- const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`)
- const playlist = res.text
-
- const videoName = `${videoUUID}-${resolution}-fragmented.mp4`
-
- const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
-
- const length = parseInt(matches[1], 10)
- const offset = parseInt(matches[2], 10)
- const range = `${offset}-${offset + length - 1}`
-
- const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, HttpStatusCode.PARTIAL_CONTENT_206, `bytes=${range}`)
-
- const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
-
- const sha256Server = resSha.body[videoName][range]
- expect(sha256(res2.body)).to.equal(sha256Server)
-}
-
-async function checkLiveSegmentHash (
- baseUrlSegment: string,
- videoUUID: string,
- segmentName: string,
- hlsPlaylist: VideoStreamingPlaylist
-) {
- const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${segmentName}`)
-
- const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
-
- const sha256Server = resSha.body[segmentName]
- expect(sha256(res2.body)).to.equal(sha256Server)
-}
-
-async function checkResolutionsInMasterPlaylist (playlistUrl: string, resolutions: number[]) {
- const res = await getPlaylist(playlistUrl)
-
- const masterPlaylist = res.text
-
- for (const resolution of resolutions) {
- const reg = new RegExp(
- '#EXT-X-STREAM-INF:BANDWIDTH=\\d+,RESOLUTION=\\d+x' + resolution + ',(FRAME-RATE=\\d+,)?CODECS="avc1.64001f,mp4a.40.2"'
- )
-
- expect(masterPlaylist).to.match(reg)
- }
-}
-
-// ---------------------------------------------------------------------------
-
-export {
- getPlaylist,
- getSegment,
- checkResolutionsInMasterPlaylist,
- getSegmentSha256,
- checkLiveSegmentHash,
- checkSegmentHash
-}