From bf54587a3e2ad9c2c186828f2a5682b91ee2cc00 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 17 Dec 2021 09:29:23 +0100 Subject: shared/ typescript types dir server-commands --- shared/extra-utils/videos/blacklist-command.ts | 76 --- shared/extra-utils/videos/captions-command.ts | 65 -- shared/extra-utils/videos/captions.ts | 21 - .../extra-utils/videos/change-ownership-command.ts | 68 --- shared/extra-utils/videos/channels-command.ts | 178 ------ shared/extra-utils/videos/channels.ts | 18 - shared/extra-utils/videos/comments-command.ts | 152 ----- shared/extra-utils/videos/history-command.ts | 58 -- shared/extra-utils/videos/imports-command.ts | 47 -- shared/extra-utils/videos/index.ts | 19 - shared/extra-utils/videos/live-command.ts | 155 ----- shared/extra-utils/videos/live.ts | 137 ----- shared/extra-utils/videos/playlists-command.ts | 280 --------- shared/extra-utils/videos/playlists.ts | 25 - shared/extra-utils/videos/services-command.ts | 29 - .../videos/streaming-playlists-command.ts | 44 -- shared/extra-utils/videos/streaming-playlists.ts | 77 --- shared/extra-utils/videos/videos-command.ts | 679 --------------------- shared/extra-utils/videos/videos.ts | 104 ---- 19 files changed, 2232 deletions(-) delete mode 100644 shared/extra-utils/videos/blacklist-command.ts delete mode 100644 shared/extra-utils/videos/captions-command.ts delete mode 100644 shared/extra-utils/videos/captions.ts delete mode 100644 shared/extra-utils/videos/change-ownership-command.ts delete mode 100644 shared/extra-utils/videos/channels-command.ts delete mode 100644 shared/extra-utils/videos/channels.ts delete mode 100644 shared/extra-utils/videos/comments-command.ts delete mode 100644 shared/extra-utils/videos/history-command.ts delete mode 100644 shared/extra-utils/videos/imports-command.ts delete mode 100644 shared/extra-utils/videos/index.ts delete mode 100644 shared/extra-utils/videos/live-command.ts delete mode 100644 shared/extra-utils/videos/live.ts delete mode 100644 shared/extra-utils/videos/playlists-command.ts delete mode 100644 shared/extra-utils/videos/playlists.ts delete mode 100644 shared/extra-utils/videos/services-command.ts delete mode 100644 shared/extra-utils/videos/streaming-playlists-command.ts delete mode 100644 shared/extra-utils/videos/streaming-playlists.ts delete mode 100644 shared/extra-utils/videos/videos-command.ts delete mode 100644 shared/extra-utils/videos/videos.ts (limited to 'shared/extra-utils/videos') diff --git a/shared/extra-utils/videos/blacklist-command.ts b/shared/extra-utils/videos/blacklist-command.ts deleted file mode 100644 index 3a2ef89ba..000000000 --- a/shared/extra-utils/videos/blacklist-command.ts +++ /dev/null @@ -1,76 +0,0 @@ - -import { HttpStatusCode, ResultList } from '@shared/models' -import { VideoBlacklist, VideoBlacklistType } from '../../models/videos' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class BlacklistCommand extends AbstractCommand { - - add (options: OverrideCommandOptions & { - videoId: number | string - reason?: string - unfederate?: boolean - }) { - const { videoId, reason, unfederate } = options - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return this.postBodyRequest({ - ...options, - - path, - fields: { reason, unfederate }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - update (options: OverrideCommandOptions & { - videoId: number | string - reason?: string - }) { - const { videoId, reason } = options - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return this.putBodyRequest({ - ...options, - - path, - fields: { reason }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - remove (options: OverrideCommandOptions & { - videoId: number | string - }) { - const { videoId } = options - const path = '/api/v1/videos/' + videoId + '/blacklist' - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - list (options: OverrideCommandOptions & { - sort?: string - type?: VideoBlacklistType - } = {}) { - const { sort, type } = options - const path = '/api/v1/videos/blacklist/' - - const query = { sort, type } - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/videos/captions-command.ts b/shared/extra-utils/videos/captions-command.ts deleted file mode 100644 index a65ea99e3..000000000 --- a/shared/extra-utils/videos/captions-command.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { HttpStatusCode, ResultList, VideoCaption } from '@shared/models' -import { buildAbsoluteFixturePath } from '../miscs' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class CaptionsCommand extends AbstractCommand { - - add (options: OverrideCommandOptions & { - videoId: string | number - language: string - fixture: string - mimeType?: string - }) { - const { videoId, language, fixture, mimeType } = options - - const path = '/api/v1/videos/' + videoId + '/captions/' + language - - const captionfile = buildAbsoluteFixturePath(fixture) - const captionfileAttach = mimeType - ? [ captionfile, { contentType: mimeType } ] - : captionfile - - return this.putUploadRequest({ - ...options, - - path, - fields: {}, - attaches: { - captionfile: captionfileAttach - }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - list (options: OverrideCommandOptions & { - videoId: string | number - }) { - const { videoId } = options - const path = '/api/v1/videos/' + videoId + '/captions' - - return this.getRequestBody>({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - delete (options: OverrideCommandOptions & { - videoId: string | number - language: string - }) { - const { videoId, language } = options - const path = '/api/v1/videos/' + videoId + '/captions/' + language - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/videos/captions.ts b/shared/extra-utils/videos/captions.ts deleted file mode 100644 index 35e722408..000000000 --- a/shared/extra-utils/videos/captions.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { expect } from 'chai' -import request from 'supertest' -import { HttpStatusCode } from '@shared/models' - -async function testCaptionFile (url: string, captionPath: string, toTest: RegExp | string) { - const res = await request(url) - .get(captionPath) - .expect(HttpStatusCode.OK_200) - - if (toTest instanceof RegExp) { - expect(res.text).to.match(toTest) - } else { - expect(res.text).to.contain(toTest) - } -} - -// --------------------------------------------------------------------------- - -export { - testCaptionFile -} diff --git a/shared/extra-utils/videos/change-ownership-command.ts b/shared/extra-utils/videos/change-ownership-command.ts deleted file mode 100644 index ad4c726ef..000000000 --- a/shared/extra-utils/videos/change-ownership-command.ts +++ /dev/null @@ -1,68 +0,0 @@ - -import { HttpStatusCode, ResultList, VideoChangeOwnership } from '@shared/models' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class ChangeOwnershipCommand extends AbstractCommand { - - create (options: OverrideCommandOptions & { - videoId: number | string - username: string - }) { - const { videoId, username } = options - const path = '/api/v1/videos/' + videoId + '/give-ownership' - - return this.postBodyRequest({ - ...options, - - path, - fields: { username }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - list (options: OverrideCommandOptions = {}) { - const path = '/api/v1/videos/ownership' - - return this.getRequestBody>({ - ...options, - - path, - query: { sort: '-createdAt' }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - accept (options: OverrideCommandOptions & { - ownershipId: number - channelId: number - }) { - const { ownershipId, channelId } = options - const path = '/api/v1/videos/ownership/' + ownershipId + '/accept' - - return this.postBodyRequest({ - ...options, - - path, - fields: { channelId }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - refuse (options: OverrideCommandOptions & { - ownershipId: number - }) { - const { ownershipId } = options - const path = '/api/v1/videos/ownership/' + ownershipId + '/refuse' - - return this.postBodyRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/videos/channels-command.ts b/shared/extra-utils/videos/channels-command.ts deleted file mode 100644 index e406e570b..000000000 --- a/shared/extra-utils/videos/channels-command.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { pick } from '@shared/core-utils' -import { ActorFollow, HttpStatusCode, ResultList, VideoChannel, VideoChannelCreateResult } from '@shared/models' -import { VideoChannelCreate } from '../../models/videos/channel/video-channel-create.model' -import { VideoChannelUpdate } from '../../models/videos/channel/video-channel-update.model' -import { unwrapBody } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class ChannelsCommand extends AbstractCommand { - - list (options: OverrideCommandOptions & { - start?: number - count?: number - sort?: string - withStats?: boolean - } = {}) { - const path = '/api/v1/video-channels' - - return this.getRequestBody>({ - ...options, - - path, - query: pick(options, [ 'start', 'count', 'sort', 'withStats' ]), - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listByAccount (options: OverrideCommandOptions & { - accountName: string - start?: number - count?: number - sort?: string - withStats?: boolean - search?: string - }) { - const { accountName, sort = 'createdAt' } = options - const path = '/api/v1/accounts/' + accountName + '/video-channels' - - return this.getRequestBody>({ - ...options, - - path, - query: { sort, ...pick(options, [ 'start', 'count', 'withStats', 'search' ]) }, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - async create (options: OverrideCommandOptions & { - attributes: Partial - }) { - const path = '/api/v1/video-channels/' - - // Default attributes - const defaultAttributes = { - displayName: 'my super video channel', - description: 'my super channel description', - support: 'my super channel support' - } - const attributes = { ...defaultAttributes, ...options.attributes } - - const body = await unwrapBody<{ videoChannel: VideoChannelCreateResult }>(this.postBodyRequest({ - ...options, - - path, - fields: attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - return body.videoChannel - } - - update (options: OverrideCommandOptions & { - channelName: string - attributes: VideoChannelUpdate - }) { - const { channelName, attributes } = options - const path = '/api/v1/video-channels/' + channelName - - return this.putBodyRequest({ - ...options, - - path, - fields: attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - delete (options: OverrideCommandOptions & { - channelName: string - }) { - const path = '/api/v1/video-channels/' + options.channelName - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - get (options: OverrideCommandOptions & { - channelName: string - }) { - const path = '/api/v1/video-channels/' + options.channelName - - return this.getRequestBody({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - updateImage (options: OverrideCommandOptions & { - fixture: string - channelName: string | number - type: 'avatar' | 'banner' - }) { - const { channelName, fixture, type } = options - - const path = `/api/v1/video-channels/${channelName}/${type}/pick` - - return this.updateImageRequest({ - ...options, - - path, - fixture, - fieldname: type + 'file', - - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - deleteImage (options: OverrideCommandOptions & { - channelName: string | number - type: 'avatar' | 'banner' - }) { - const { channelName, type } = options - - const path = `/api/v1/video-channels/${channelName}/${type}` - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - listFollowers (options: OverrideCommandOptions & { - channelName: string - start?: number - count?: number - sort?: string - search?: string - }) { - const { channelName, start, count, sort, search } = options - const path = '/api/v1/video-channels/' + channelName + '/followers' - - const query = { start, count, sort, search } - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/videos/channels.ts b/shared/extra-utils/videos/channels.ts deleted file mode 100644 index 756c47453..000000000 --- a/shared/extra-utils/videos/channels.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { PeerTubeServer } from '../server/server' - -function setDefaultVideoChannel (servers: PeerTubeServer[]) { - const tasks: Promise[] = [] - - for (const server of servers) { - const p = server.users.getMyInfo() - .then(user => { server.store.channel = user.videoChannels[0] }) - - tasks.push(p) - } - - return Promise.all(tasks) -} - -export { - setDefaultVideoChannel -} diff --git a/shared/extra-utils/videos/comments-command.ts b/shared/extra-utils/videos/comments-command.ts deleted file mode 100644 index f0d163a07..000000000 --- a/shared/extra-utils/videos/comments-command.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { pick } from 'lodash' -import { HttpStatusCode, ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@shared/models' -import { unwrapBody } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class CommentsCommand extends AbstractCommand { - - private lastVideoId: number | string - private lastThreadId: number - private lastReplyId: number - - listForAdmin (options: OverrideCommandOptions & { - start?: number - count?: number - sort?: string - isLocal?: boolean - search?: string - searchAccount?: string - searchVideo?: string - } = {}) { - const { sort = '-createdAt' } = options - const path = '/api/v1/videos/comments' - - const query = { sort, ...pick(options, [ 'start', 'count', 'isLocal', 'search', 'searchAccount', 'searchVideo' ]) } - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listThreads (options: OverrideCommandOptions & { - videoId: number | string - start?: number - count?: number - sort?: string - }) { - const { start, count, sort, videoId } = options - const path = '/api/v1/videos/' + videoId + '/comment-threads' - - return this.getRequestBody({ - ...options, - - path, - query: { start, count, sort }, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getThread (options: OverrideCommandOptions & { - videoId: number | string - threadId: number - }) { - const { videoId, threadId } = options - const path = '/api/v1/videos/' + videoId + '/comment-threads/' + threadId - - return this.getRequestBody({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - async createThread (options: OverrideCommandOptions & { - videoId: number | string - text: string - }) { - const { videoId, text } = options - const path = '/api/v1/videos/' + videoId + '/comment-threads' - - const body = await unwrapBody<{ comment: VideoComment }>(this.postBodyRequest({ - ...options, - - path, - fields: { text }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - this.lastThreadId = body.comment?.id - this.lastVideoId = videoId - - return body.comment - } - - async addReply (options: OverrideCommandOptions & { - videoId: number | string - toCommentId: number - text: string - }) { - const { videoId, toCommentId, text } = options - const path = '/api/v1/videos/' + videoId + '/comments/' + toCommentId - - const body = await unwrapBody<{ comment: VideoComment }>(this.postBodyRequest({ - ...options, - - path, - fields: { text }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - this.lastReplyId = body.comment?.id - - return body.comment - } - - async addReplyToLastReply (options: OverrideCommandOptions & { - text: string - }) { - return this.addReply({ ...options, videoId: this.lastVideoId, toCommentId: this.lastReplyId }) - } - - async addReplyToLastThread (options: OverrideCommandOptions & { - text: string - }) { - return this.addReply({ ...options, videoId: this.lastVideoId, toCommentId: this.lastThreadId }) - } - - async findCommentId (options: OverrideCommandOptions & { - videoId: number | string - text: string - }) { - const { videoId, text } = options - const { data } = await this.listThreads({ videoId, count: 25, sort: '-createdAt' }) - - return data.find(c => c.text === text).id - } - - delete (options: OverrideCommandOptions & { - videoId: number | string - commentId: number - }) { - const { videoId, commentId } = options - const path = '/api/v1/videos/' + videoId + '/comments/' + commentId - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/videos/history-command.ts b/shared/extra-utils/videos/history-command.ts deleted file mode 100644 index 13b7150c1..000000000 --- a/shared/extra-utils/videos/history-command.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { HttpStatusCode, ResultList, Video } from '@shared/models' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class HistoryCommand extends AbstractCommand { - - wathVideo (options: OverrideCommandOptions & { - videoId: number | string - currentTime: number - }) { - const { videoId, currentTime } = options - - const path = '/api/v1/videos/' + videoId + '/watching' - const fields = { currentTime } - - return this.putBodyRequest({ - ...options, - - path, - fields, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - list (options: OverrideCommandOptions & { - search?: string - } = {}) { - const { search } = options - const path = '/api/v1/users/me/history/videos' - - return this.getRequestBody>({ - ...options, - - path, - query: { - search - }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - remove (options: OverrideCommandOptions & { - beforeDate?: string - } = {}) { - const { beforeDate } = options - const path = '/api/v1/users/me/history/videos/remove' - - return this.postBodyRequest({ - ...options, - - path, - fields: { beforeDate }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } -} diff --git a/shared/extra-utils/videos/imports-command.ts b/shared/extra-utils/videos/imports-command.ts deleted file mode 100644 index e4944694d..000000000 --- a/shared/extra-utils/videos/imports-command.ts +++ /dev/null @@ -1,47 +0,0 @@ - -import { HttpStatusCode, ResultList } from '@shared/models' -import { VideoImport, VideoImportCreate } from '../../models/videos' -import { unwrapBody } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class ImportsCommand extends AbstractCommand { - - importVideo (options: OverrideCommandOptions & { - attributes: VideoImportCreate & { torrentfile?: string } - }) { - const { attributes } = options - const path = '/api/v1/videos/imports' - - let attaches: any = {} - if (attributes.torrentfile) attaches = { torrentfile: attributes.torrentfile } - - return unwrapBody(this.postUploadRequest({ - ...options, - - path, - attaches, - fields: options.attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - } - - getMyVideoImports (options: OverrideCommandOptions & { - sort?: string - } = {}) { - const { sort } = options - const path = '/api/v1/users/me/videos/imports' - - const query = {} - if (sort) query['sort'] = sort - - return this.getRequestBody>({ - ...options, - - path, - query: { sort }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/videos/index.ts b/shared/extra-utils/videos/index.ts deleted file mode 100644 index 26e663f46..000000000 --- a/shared/extra-utils/videos/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -export * from './blacklist-command' -export * from './captions-command' -export * from './captions' -export * from './change-ownership-command' -export * from './channels' -export * from './channels-command' -export * from './comments-command' -export * from './history-command' -export * from './imports-command' -export * from './live-command' -export * from './live' -export * from './playlists-command' -export * from './playlists' -export * from './services-command' -export * from './streaming-playlists-command' -export * from './streaming-playlists' -export * from './comments-command' -export * from './videos-command' -export * from './videos' diff --git a/shared/extra-utils/videos/live-command.ts b/shared/extra-utils/videos/live-command.ts deleted file mode 100644 index 74f5d3089..000000000 --- a/shared/extra-utils/videos/live-command.ts +++ /dev/null @@ -1,155 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { readdir } from 'fs-extra' -import { omit } from 'lodash' -import { join } from 'path' -import { HttpStatusCode, LiveVideo, LiveVideoCreate, LiveVideoUpdate, VideoCreateResult, VideoDetails, VideoState } from '@shared/models' -import { wait } from '../miscs' -import { unwrapBody } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' -import { sendRTMPStream, testFfmpegStreamError } from './live' - -export class LiveCommand extends AbstractCommand { - - get (options: OverrideCommandOptions & { - videoId: number | string - }) { - const path = '/api/v1/videos/live' - - return this.getRequestBody({ - ...options, - - path: path + '/' + options.videoId, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - update (options: OverrideCommandOptions & { - videoId: number | string - fields: LiveVideoUpdate - }) { - const { videoId, fields } = options - const path = '/api/v1/videos/live' - - return this.putBodyRequest({ - ...options, - - path: path + '/' + videoId, - fields, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - async create (options: OverrideCommandOptions & { - fields: LiveVideoCreate - }) { - const { fields } = options - const path = '/api/v1/videos/live' - - const attaches: any = {} - if (fields.thumbnailfile) attaches.thumbnailfile = fields.thumbnailfile - if (fields.previewfile) attaches.previewfile = fields.previewfile - - const body = await unwrapBody<{ video: VideoCreateResult }>(this.postUploadRequest({ - ...options, - - path, - attaches, - fields: omit(fields, 'thumbnailfile', 'previewfile'), - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - return body.video - } - - async sendRTMPStreamInVideo (options: OverrideCommandOptions & { - videoId: number | string - fixtureName?: string - copyCodecs?: boolean - }) { - const { videoId, fixtureName, copyCodecs } = options - const videoLive = await this.get({ videoId }) - - return sendRTMPStream({ rtmpBaseUrl: videoLive.rtmpUrl, streamKey: videoLive.streamKey, fixtureName, copyCodecs }) - } - - async runAndTestStreamError (options: OverrideCommandOptions & { - videoId: number | string - shouldHaveError: boolean - }) { - const command = await this.sendRTMPStreamInVideo(options) - - return testFfmpegStreamError(command, options.shouldHaveError) - } - - waitUntilPublished (options: OverrideCommandOptions & { - videoId: number | string - }) { - const { videoId } = options - return this.waitUntilState({ videoId, state: VideoState.PUBLISHED }) - } - - waitUntilWaiting (options: OverrideCommandOptions & { - videoId: number | string - }) { - const { videoId } = options - return this.waitUntilState({ videoId, state: VideoState.WAITING_FOR_LIVE }) - } - - waitUntilEnded (options: OverrideCommandOptions & { - videoId: number | string - }) { - const { videoId } = options - return this.waitUntilState({ videoId, state: VideoState.LIVE_ENDED }) - } - - waitUntilSegmentGeneration (options: OverrideCommandOptions & { - videoUUID: string - resolution: number - segment: number - }) { - const { resolution, segment, videoUUID } = options - const segmentName = `${resolution}-00000${segment}.ts` - - return this.server.servers.waitUntilLog(`${videoUUID}/${segmentName}`, 2, false) - } - - async waitUntilSaved (options: OverrideCommandOptions & { - videoId: number | string - }) { - let video: VideoDetails - - do { - video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) - - await wait(500) - } while (video.isLive === true || video.state.id !== VideoState.PUBLISHED) - } - - async countPlaylists (options: OverrideCommandOptions & { - videoUUID: string - }) { - const basePath = this.server.servers.buildDirectory('streaming-playlists') - const hlsPath = join(basePath, 'hls', options.videoUUID) - - const files = await readdir(hlsPath) - - return files.filter(f => f.endsWith('.m3u8')).length - } - - private async waitUntilState (options: OverrideCommandOptions & { - videoId: number | string - state: VideoState - }) { - let video: VideoDetails - - do { - video = await this.server.videos.getWithToken({ token: options.token, id: options.videoId }) - - await wait(500) - } while (video.state.id !== options.state) - } -} diff --git a/shared/extra-utils/videos/live.ts b/shared/extra-utils/videos/live.ts deleted file mode 100644 index d3665bc90..000000000 --- a/shared/extra-utils/videos/live.ts +++ /dev/null @@ -1,137 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ - -import { expect } from 'chai' -import ffmpeg, { FfmpegCommand } from 'fluent-ffmpeg' -import { pathExists, readdir } from 'fs-extra' -import { join } from 'path' -import { buildAbsoluteFixturePath, wait } from '../miscs' -import { PeerTubeServer } from '../server/server' - -function sendRTMPStream (options: { - rtmpBaseUrl: string - streamKey: string - fixtureName?: string // default video_short.mp4 - copyCodecs?: boolean // default false -}) { - const { rtmpBaseUrl, streamKey, fixtureName = 'video_short.mp4', copyCodecs = false } = options - - const fixture = buildAbsoluteFixturePath(fixtureName) - - const command = ffmpeg(fixture) - command.inputOption('-stream_loop -1') - command.inputOption('-re') - - if (copyCodecs) { - command.outputOption('-c copy') - } else { - command.outputOption('-c:v libx264') - command.outputOption('-g 50') - command.outputOption('-keyint_min 2') - command.outputOption('-r 60') - } - - command.outputOption('-f flv') - - const rtmpUrl = rtmpBaseUrl + '/' + streamKey - command.output(rtmpUrl) - - command.on('error', err => { - if (err?.message?.includes('Exiting normally')) return - - if (process.env.DEBUG) console.error(err) - }) - - if (process.env.DEBUG) { - command.on('stderr', data => console.log(data)) - } - - command.run() - - return command -} - -function waitFfmpegUntilError (command: FfmpegCommand, successAfterMS = 10000) { - return new Promise((res, rej) => { - command.on('error', err => { - return rej(err) - }) - - setTimeout(() => { - res() - }, successAfterMS) - }) -} - -async function testFfmpegStreamError (command: FfmpegCommand, shouldHaveError: boolean) { - let error: Error - - try { - await waitFfmpegUntilError(command, 35000) - } catch (err) { - error = err - } - - await stopFfmpeg(command) - - if (shouldHaveError && !error) throw new Error('Ffmpeg did not have an error') - if (!shouldHaveError && error) throw error -} - -async function stopFfmpeg (command: FfmpegCommand) { - command.kill('SIGINT') - - await wait(500) -} - -async function waitUntilLivePublishedOnAllServers (servers: PeerTubeServer[], videoId: string) { - for (const server of servers) { - await server.live.waitUntilPublished({ videoId }) - } -} - -async function waitUntilLiveSavedOnAllServers (servers: PeerTubeServer[], videoId: string) { - for (const server of servers) { - await server.live.waitUntilSaved({ videoId }) - } -} - -async function checkLiveCleanupAfterSave (server: PeerTubeServer, videoUUID: string, resolutions: number[] = []) { - const basePath = server.servers.buildDirectory('streaming-playlists') - const hlsPath = join(basePath, 'hls', videoUUID) - - if (resolutions.length === 0) { - const result = await pathExists(hlsPath) - expect(result).to.be.false - - return - } - - const files = await readdir(hlsPath) - - // fragmented file and playlist per resolution + master playlist + segments sha256 json file - expect(files).to.have.lengthOf(resolutions.length * 2 + 2) - - for (const resolution of resolutions) { - const fragmentedFile = files.find(f => f.endsWith(`-${resolution}-fragmented.mp4`)) - expect(fragmentedFile).to.exist - - const playlistFile = files.find(f => f.endsWith(`${resolution}.m3u8`)) - expect(playlistFile).to.exist - } - - const masterPlaylistFile = files.find(f => f.endsWith('-master.m3u8')) - expect(masterPlaylistFile).to.exist - - const shaFile = files.find(f => f.endsWith('-segments-sha256.json')) - expect(shaFile).to.exist -} - -export { - sendRTMPStream, - waitFfmpegUntilError, - testFfmpegStreamError, - stopFfmpeg, - waitUntilLivePublishedOnAllServers, - waitUntilLiveSavedOnAllServers, - checkLiveCleanupAfterSave -} diff --git a/shared/extra-utils/videos/playlists-command.ts b/shared/extra-utils/videos/playlists-command.ts deleted file mode 100644 index ce23900d3..000000000 --- a/shared/extra-utils/videos/playlists-command.ts +++ /dev/null @@ -1,280 +0,0 @@ -import { omit } from 'lodash' -import { pick } from '@shared/core-utils' -import { - BooleanBothQuery, - HttpStatusCode, - ResultList, - VideoExistInPlaylist, - VideoPlaylist, - VideoPlaylistCreate, - VideoPlaylistCreateResult, - VideoPlaylistElement, - VideoPlaylistElementCreate, - VideoPlaylistElementCreateResult, - VideoPlaylistElementUpdate, - VideoPlaylistReorder, - VideoPlaylistType, - VideoPlaylistUpdate -} from '@shared/models' -import { unwrapBody } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class PlaylistsCommand extends AbstractCommand { - - list (options: OverrideCommandOptions & { - start?: number - count?: number - sort?: string - }) { - const path = '/api/v1/video-playlists' - const query = pick(options, [ 'start', 'count', 'sort' ]) - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listByChannel (options: OverrideCommandOptions & { - handle: string - start?: number - count?: number - sort?: string - }) { - const path = '/api/v1/video-channels/' + options.handle + '/video-playlists' - const query = pick(options, [ 'start', 'count', 'sort' ]) - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listByAccount (options: OverrideCommandOptions & { - handle: string - start?: number - count?: number - sort?: string - search?: string - playlistType?: VideoPlaylistType - }) { - const path = '/api/v1/accounts/' + options.handle + '/video-playlists' - const query = pick(options, [ 'start', 'count', 'sort', 'search', 'playlistType' ]) - - return this.getRequestBody>({ - ...options, - - path, - query, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - get (options: OverrideCommandOptions & { - playlistId: number | string - }) { - const { playlistId } = options - const path = '/api/v1/video-playlists/' + playlistId - - return this.getRequestBody({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listVideos (options: OverrideCommandOptions & { - playlistId: number | string - start?: number - count?: number - query?: { nsfw?: BooleanBothQuery } - }) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' - const query = options.query ?? {} - - return this.getRequestBody>({ - ...options, - - path, - query: { - ...query, - start: options.start, - count: options.count - }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - delete (options: OverrideCommandOptions & { - playlistId: number | string - }) { - const path = '/api/v1/video-playlists/' + options.playlistId - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - async create (options: OverrideCommandOptions & { - attributes: VideoPlaylistCreate - }) { - const path = '/api/v1/video-playlists' - - const fields = omit(options.attributes, 'thumbnailfile') - - const attaches = options.attributes.thumbnailfile - ? { thumbnailfile: options.attributes.thumbnailfile } - : {} - - const body = await unwrapBody<{ videoPlaylist: VideoPlaylistCreateResult }>(this.postUploadRequest({ - ...options, - - path, - fields, - attaches, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - return body.videoPlaylist - } - - update (options: OverrideCommandOptions & { - attributes: VideoPlaylistUpdate - playlistId: number | string - }) { - const path = '/api/v1/video-playlists/' + options.playlistId - - const fields = omit(options.attributes, 'thumbnailfile') - - const attaches = options.attributes.thumbnailfile - ? { thumbnailfile: options.attributes.thumbnailfile } - : {} - - return this.putUploadRequest({ - ...options, - - path, - fields, - attaches, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - async addElement (options: OverrideCommandOptions & { - playlistId: number | string - attributes: VideoPlaylistElementCreate | { videoId: string } - }) { - const attributes = { - ...options.attributes, - - videoId: await this.server.videos.getId({ ...options, uuid: options.attributes.videoId }) - } - - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos' - - const body = await unwrapBody<{ videoPlaylistElement: VideoPlaylistElementCreateResult }>(this.postBodyRequest({ - ...options, - - path, - fields: attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - - return body.videoPlaylistElement - } - - updateElement (options: OverrideCommandOptions & { - playlistId: number | string - elementId: number | string - attributes: VideoPlaylistElementUpdate - }) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.elementId - - return this.putBodyRequest({ - ...options, - - path, - fields: options.attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - removeElement (options: OverrideCommandOptions & { - playlistId: number | string - elementId: number - }) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.elementId - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - reorderElements (options: OverrideCommandOptions & { - playlistId: number | string - attributes: VideoPlaylistReorder - }) { - const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/reorder' - - return this.postBodyRequest({ - ...options, - - path, - fields: options.attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - getPrivacies (options: OverrideCommandOptions = {}) { - const path = '/api/v1/video-playlists/privacies' - - return this.getRequestBody<{ [ id: number ]: string }>({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - videosExist (options: OverrideCommandOptions & { - videoIds: number[] - }) { - const { videoIds } = options - const path = '/api/v1/users/me/video-playlists/videos-exist' - - return this.getRequestBody({ - ...options, - - path, - query: { videoIds }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/videos/playlists.ts b/shared/extra-utils/videos/playlists.ts deleted file mode 100644 index 3dde52bb9..000000000 --- a/shared/extra-utils/videos/playlists.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { expect } from 'chai' -import { readdir } from 'fs-extra' -import { join } from 'path' -import { root } from '../miscs' - -async function checkPlaylistFilesWereRemoved ( - playlistUUID: string, - internalServerNumber: number, - directories = [ 'thumbnails' ] -) { - const testDirectory = 'test' + internalServerNumber - - for (const directory of directories) { - const directoryPath = join(root(), testDirectory, directory) - - const files = await readdir(directoryPath) - for (const file of files) { - expect(file).to.not.contain(playlistUUID) - } - } -} - -export { - checkPlaylistFilesWereRemoved -} diff --git a/shared/extra-utils/videos/services-command.ts b/shared/extra-utils/videos/services-command.ts deleted file mode 100644 index 06760df42..000000000 --- a/shared/extra-utils/videos/services-command.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { HttpStatusCode } from '@shared/models' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class ServicesCommand extends AbstractCommand { - - getOEmbed (options: OverrideCommandOptions & { - oembedUrl: string - format?: string - maxHeight?: number - maxWidth?: number - }) { - const path = '/services/oembed' - const query = { - url: options.oembedUrl, - format: options.format, - maxheight: options.maxHeight, - maxwidth: options.maxWidth - } - - return this.getRequest({ - ...options, - - path, - query, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } -} diff --git a/shared/extra-utils/videos/streaming-playlists-command.ts b/shared/extra-utils/videos/streaming-playlists-command.ts deleted file mode 100644 index 5d40d35cb..000000000 --- a/shared/extra-utils/videos/streaming-playlists-command.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { HttpStatusCode } from '@shared/models' -import { unwrapBody, unwrapTextOrDecode, unwrapBodyOrDecodeToJSON } from '../requests' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export class StreamingPlaylistsCommand extends AbstractCommand { - - get (options: OverrideCommandOptions & { - url: string - }) { - return unwrapTextOrDecode(this.getRawRequest({ - ...options, - - url: options.url, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - } - - getSegment (options: OverrideCommandOptions & { - url: string - range?: string - }) { - return unwrapBody(this.getRawRequest({ - ...options, - - url: options.url, - range: options.range, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - } - - getSegmentSha256 (options: OverrideCommandOptions & { - url: string - }) { - return unwrapBodyOrDecodeToJSON<{ [ id: string ]: string }>(this.getRawRequest({ - ...options, - - url: options.url, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - } -} diff --git a/shared/extra-utils/videos/streaming-playlists.ts b/shared/extra-utils/videos/streaming-playlists.ts deleted file mode 100644 index 0451c0efe..000000000 --- a/shared/extra-utils/videos/streaming-playlists.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { expect } from 'chai' -import { basename } from 'path' -import { sha256 } from '@shared/core-utils/crypto' -import { removeFragmentedMP4Ext } from '@shared/core-utils' -import { HttpStatusCode, VideoStreamingPlaylist } from '@shared/models' -import { PeerTubeServer } from '../server' - -async function checkSegmentHash (options: { - server: PeerTubeServer - baseUrlPlaylist: string - baseUrlSegment: string - resolution: number - hlsPlaylist: VideoStreamingPlaylist -}) { - const { server, baseUrlPlaylist, baseUrlSegment, resolution, hlsPlaylist } = options - const command = server.streamingPlaylists - - const file = hlsPlaylist.files.find(f => f.resolution.id === resolution) - const videoName = basename(file.fileUrl) - - const playlist = await command.get({ url: `${baseUrlPlaylist}/${removeFragmentedMP4Ext(videoName)}.m3u8` }) - - 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}/${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: PeerTubeServer - baseUrlSegment: string - videoUUID: string - segmentName: string - hlsPlaylist: VideoStreamingPlaylist -}) { - const { server, baseUrlSegment, videoUUID, segmentName, hlsPlaylist } = options - const command = server.streamingPlaylists - - 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: PeerTubeServer - playlistUrl: string - resolutions: number[] -}) { - const { server, playlistUrl, resolutions } = options - - const masterPlaylist = await server.streamingPlaylists.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 -} diff --git a/shared/extra-utils/videos/videos-command.ts b/shared/extra-utils/videos/videos-command.ts deleted file mode 100644 index 8ea828b40..000000000 --- a/shared/extra-utils/videos/videos-command.ts +++ /dev/null @@ -1,679 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ - -import { expect } from 'chai' -import { createReadStream, stat } from 'fs-extra' -import got, { Response as GotResponse } from 'got' -import { omit } from 'lodash' -import validator from 'validator' -import { buildUUID } from '@shared/core-utils/uuid' -import { pick } from '@shared/core-utils' -import { - HttpStatusCode, - ResultList, - UserVideoRateType, - Video, - VideoCreate, - VideoCreateResult, - VideoDetails, - VideoFileMetadata, - VideoPrivacy, - VideosCommonQuery, - VideoTranscodingCreate -} from '@shared/models' -import { buildAbsoluteFixturePath, wait } from '../miscs' -import { unwrapBody } from '../requests' -import { waitJobs } from '../server' -import { AbstractCommand, OverrideCommandOptions } from '../shared' - -export type VideoEdit = Partial> & { - fixture?: string - thumbnailfile?: string - previewfile?: string -} - -export class VideosCommand extends AbstractCommand { - getCategories (options: OverrideCommandOptions = {}) { - const path = '/api/v1/videos/categories' - - return this.getRequestBody<{ [id: number]: string }>({ - ...options, - path, - - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getLicences (options: OverrideCommandOptions = {}) { - const path = '/api/v1/videos/licences' - - return this.getRequestBody<{ [id: number]: string }>({ - ...options, - path, - - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getLanguages (options: OverrideCommandOptions = {}) { - const path = '/api/v1/videos/languages' - - return this.getRequestBody<{ [id: string]: string }>({ - ...options, - path, - - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getPrivacies (options: OverrideCommandOptions = {}) { - const path = '/api/v1/videos/privacies' - - return this.getRequestBody<{ [id in VideoPrivacy]: string }>({ - ...options, - path, - - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - // --------------------------------------------------------------------------- - - getDescription (options: OverrideCommandOptions & { - descriptionPath: string - }) { - return this.getRequestBody<{ description: string }>({ - ...options, - path: options.descriptionPath, - - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getFileMetadata (options: OverrideCommandOptions & { - url: string - }) { - return unwrapBody(this.getRawRequest({ - ...options, - - url: options.url, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - })) - } - - // --------------------------------------------------------------------------- - - view (options: OverrideCommandOptions & { - id: number | string - xForwardedFor?: string - }) { - const { id, xForwardedFor } = options - const path = '/api/v1/videos/' + id + '/views' - - return this.postBodyRequest({ - ...options, - - path, - xForwardedFor, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - rate (options: OverrideCommandOptions & { - id: number | string - rating: UserVideoRateType - }) { - const { id, rating } = options - const path = '/api/v1/videos/' + id + '/rate' - - return this.putBodyRequest({ - ...options, - - path, - fields: { rating }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - // --------------------------------------------------------------------------- - - get (options: OverrideCommandOptions & { - id: number | string - }) { - const path = '/api/v1/videos/' + options.id - - return this.getRequestBody({ - ...options, - - path, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - getWithToken (options: OverrideCommandOptions & { - id: number | string - }) { - return this.get({ - ...options, - - token: this.buildCommonRequestToken({ ...options, implicitToken: true }) - }) - } - - async getId (options: OverrideCommandOptions & { - uuid: number | string - }) { - const { uuid } = options - - if (validator.isUUID('' + uuid) === false) return uuid as number - - const { id } = await this.get({ ...options, id: uuid }) - - return id - } - - async listFiles (options: OverrideCommandOptions & { - id: number | string - }) { - const video = await this.get(options) - - const files = video.files || [] - const hlsFiles = video.streamingPlaylists[0]?.files || [] - - return files.concat(hlsFiles) - } - - // --------------------------------------------------------------------------- - - listMyVideos (options: OverrideCommandOptions & { - start?: number - count?: number - sort?: string - search?: string - isLive?: boolean - channelId?: number - } = {}) { - const path = '/api/v1/users/me/videos' - - return this.getRequestBody>({ - ...options, - - path, - query: pick(options, [ 'start', 'count', 'sort', 'search', 'isLive', 'channelId' ]), - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - // --------------------------------------------------------------------------- - - list (options: OverrideCommandOptions & VideosCommonQuery = {}) { - const path = '/api/v1/videos' - - const query = this.buildListQuery(options) - - return this.getRequestBody>({ - ...options, - - path, - query: { sort: 'name', ...query }, - implicitToken: false, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listWithToken (options: OverrideCommandOptions & VideosCommonQuery = {}) { - return this.list({ - ...options, - - token: this.buildCommonRequestToken({ ...options, implicitToken: true }) - }) - } - - listByAccount (options: OverrideCommandOptions & VideosCommonQuery & { - handle: string - }) { - const { handle, search } = options - const path = '/api/v1/accounts/' + handle + '/videos' - - return this.getRequestBody>({ - ...options, - - path, - query: { search, ...this.buildListQuery(options) }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - listByChannel (options: OverrideCommandOptions & VideosCommonQuery & { - handle: string - }) { - const { handle } = options - const path = '/api/v1/video-channels/' + handle + '/videos' - - return this.getRequestBody>({ - ...options, - - path, - query: this.buildListQuery(options), - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - }) - } - - // --------------------------------------------------------------------------- - - async find (options: OverrideCommandOptions & { - name: string - }) { - const { data } = await this.list(options) - - return data.find(v => v.name === options.name) - } - - // --------------------------------------------------------------------------- - - update (options: OverrideCommandOptions & { - id: number | string - attributes?: VideoEdit - }) { - const { id, attributes = {} } = options - const path = '/api/v1/videos/' + id - - // Upload request - if (attributes.thumbnailfile || attributes.previewfile) { - const attaches: any = {} - if (attributes.thumbnailfile) attaches.thumbnailfile = attributes.thumbnailfile - if (attributes.previewfile) attaches.previewfile = attributes.previewfile - - return this.putUploadRequest({ - ...options, - - path, - fields: options.attributes, - attaches: { - thumbnailfile: attributes.thumbnailfile, - previewfile: attributes.previewfile - }, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - return this.putBodyRequest({ - ...options, - - path, - fields: options.attributes, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - remove (options: OverrideCommandOptions & { - id: number | string - }) { - const path = '/api/v1/videos/' + options.id - - return unwrapBody(this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - })) - } - - async removeAll () { - const { data } = await this.list() - - for (const v of data) { - await this.remove({ id: v.id }) - } - } - - // --------------------------------------------------------------------------- - - async upload (options: OverrideCommandOptions & { - attributes?: VideoEdit - mode?: 'legacy' | 'resumable' // default legacy - } = {}) { - const { mode = 'legacy' } = options - let defaultChannelId = 1 - - try { - const { videoChannels } = await this.server.users.getMyInfo({ token: options.token }) - defaultChannelId = videoChannels[0].id - } catch (e) { /* empty */ } - - // Override default attributes - const attributes = { - name: 'my super video', - category: 5, - licence: 4, - language: 'zh', - channelId: defaultChannelId, - nsfw: true, - waitTranscoding: false, - description: 'my super description', - support: 'my super support text', - tags: [ 'tag' ], - privacy: VideoPrivacy.PUBLIC, - commentsEnabled: true, - downloadEnabled: true, - fixture: 'video_short.webm', - - ...options.attributes - } - - const created = mode === 'legacy' - ? await this.buildLegacyUpload({ ...options, attributes }) - : await this.buildResumeUpload({ ...options, attributes }) - - // Wait torrent generation - const expectedStatus = this.buildExpectedStatus({ ...options, defaultExpectedStatus: HttpStatusCode.OK_200 }) - if (expectedStatus === HttpStatusCode.OK_200) { - let video: VideoDetails - - do { - video = await this.getWithToken({ ...options, id: created.uuid }) - - await wait(50) - } while (!video.files[0].torrentUrl) - } - - return created - } - - async buildLegacyUpload (options: OverrideCommandOptions & { - attributes: VideoEdit - }): Promise { - const path = '/api/v1/videos/upload' - - return unwrapBody<{ video: VideoCreateResult }>(this.postUploadRequest({ - ...options, - - path, - fields: this.buildUploadFields(options.attributes), - attaches: this.buildUploadAttaches(options.attributes), - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.OK_200 - })).then(body => body.video || body as any) - } - - async buildResumeUpload (options: OverrideCommandOptions & { - attributes: VideoEdit - }): Promise { - const { attributes, expectedStatus } = options - - let size = 0 - let videoFilePath: string - let mimetype = 'video/mp4' - - if (attributes.fixture) { - videoFilePath = buildAbsoluteFixturePath(attributes.fixture) - size = (await stat(videoFilePath)).size - - if (videoFilePath.endsWith('.mkv')) { - mimetype = 'video/x-matroska' - } else if (videoFilePath.endsWith('.webm')) { - mimetype = 'video/webm' - } - } - - // Do not check status automatically, we'll check it manually - const initializeSessionRes = await this.prepareResumableUpload({ ...options, expectedStatus: null, attributes, size, mimetype }) - const initStatus = initializeSessionRes.status - - if (videoFilePath && initStatus === HttpStatusCode.CREATED_201) { - const locationHeader = initializeSessionRes.header['location'] - expect(locationHeader).to.not.be.undefined - - const pathUploadId = locationHeader.split('?')[1] - - const result = await this.sendResumableChunks({ ...options, pathUploadId, videoFilePath, size }) - - if (result.statusCode === HttpStatusCode.OK_200) { - await this.endResumableUpload({ ...options, expectedStatus: HttpStatusCode.NO_CONTENT_204, pathUploadId }) - } - - return result.body?.video || result.body as any - } - - const expectedInitStatus = expectedStatus === HttpStatusCode.OK_200 - ? HttpStatusCode.CREATED_201 - : expectedStatus - - expect(initStatus).to.equal(expectedInitStatus) - - return initializeSessionRes.body.video || initializeSessionRes.body - } - - async prepareResumableUpload (options: OverrideCommandOptions & { - attributes: VideoEdit - size: number - mimetype: string - - originalName?: string - lastModified?: number - }) { - const { attributes, originalName, lastModified, size, mimetype } = options - - const path = '/api/v1/videos/upload-resumable' - - return this.postUploadRequest({ - ...options, - - path, - headers: { - 'X-Upload-Content-Type': mimetype, - 'X-Upload-Content-Length': size.toString() - }, - fields: { - filename: attributes.fixture, - originalName, - lastModified, - - ...this.buildUploadFields(options.attributes) - }, - - // Fixture will be sent later - attaches: this.buildUploadAttaches(omit(options.attributes, 'fixture')), - implicitToken: true, - - defaultExpectedStatus: null - }) - } - - sendResumableChunks (options: OverrideCommandOptions & { - pathUploadId: string - videoFilePath: string - size: number - contentLength?: number - contentRangeBuilder?: (start: number, chunk: any) => string - }) { - const { pathUploadId, videoFilePath, size, contentLength, contentRangeBuilder, expectedStatus = HttpStatusCode.OK_200 } = options - - const path = '/api/v1/videos/upload-resumable' - let start = 0 - - const token = this.buildCommonRequestToken({ ...options, implicitToken: true }) - const url = this.server.url - - const readable = createReadStream(videoFilePath, { highWaterMark: 8 * 1024 }) - return new Promise>((resolve, reject) => { - readable.on('data', async function onData (chunk) { - readable.pause() - - const headers = { - 'Authorization': 'Bearer ' + token, - 'Content-Type': 'application/octet-stream', - 'Content-Range': contentRangeBuilder - ? contentRangeBuilder(start, chunk) - : `bytes ${start}-${start + chunk.length - 1}/${size}`, - 'Content-Length': contentLength ? contentLength + '' : chunk.length + '' - } - - const res = await got<{ video: VideoCreateResult }>({ - url, - method: 'put', - headers, - path: path + '?' + pathUploadId, - body: chunk, - responseType: 'json', - throwHttpErrors: false - }) - - start += chunk.length - - if (res.statusCode === expectedStatus) { - return resolve(res) - } - - if (res.statusCode !== HttpStatusCode.PERMANENT_REDIRECT_308) { - readable.off('data', onData) - return reject(new Error('Incorrect transient behaviour sending intermediary chunks')) - } - - readable.resume() - }) - }) - } - - endResumableUpload (options: OverrideCommandOptions & { - pathUploadId: string - }) { - return this.deleteRequest({ - ...options, - - path: '/api/v1/videos/upload-resumable', - rawQuery: options.pathUploadId, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - quickUpload (options: OverrideCommandOptions & { - name: string - nsfw?: boolean - privacy?: VideoPrivacy - fixture?: string - }) { - const attributes: VideoEdit = { name: options.name } - if (options.nsfw) attributes.nsfw = options.nsfw - if (options.privacy) attributes.privacy = options.privacy - if (options.fixture) attributes.fixture = options.fixture - - return this.upload({ ...options, attributes }) - } - - async randomUpload (options: OverrideCommandOptions & { - wait?: boolean // default true - additionalParams?: VideoEdit & { prefixName?: string } - } = {}) { - const { wait = true, additionalParams } = options - const prefixName = additionalParams?.prefixName || '' - const name = prefixName + buildUUID() - - const attributes = { name, ...additionalParams } - - const result = await this.upload({ ...options, attributes }) - - if (wait) await waitJobs([ this.server ]) - - return { ...result, name } - } - - // --------------------------------------------------------------------------- - - removeHLSFiles (options: OverrideCommandOptions & { - videoId: number | string - }) { - const path = '/api/v1/videos/' + options.videoId + '/hls' - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - removeWebTorrentFiles (options: OverrideCommandOptions & { - videoId: number | string - }) { - const path = '/api/v1/videos/' + options.videoId + '/webtorrent' - - return this.deleteRequest({ - ...options, - - path, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - runTranscoding (options: OverrideCommandOptions & { - videoId: number | string - transcodingType: 'hls' | 'webtorrent' - }) { - const path = '/api/v1/videos/' + options.videoId + '/transcoding' - - const fields: VideoTranscodingCreate = pick(options, [ 'transcodingType' ]) - - return this.postBodyRequest({ - ...options, - - path, - fields, - implicitToken: true, - defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204 - }) - } - - // --------------------------------------------------------------------------- - - private buildListQuery (options: VideosCommonQuery) { - return pick(options, [ - 'start', - 'count', - 'sort', - 'nsfw', - 'isLive', - 'categoryOneOf', - 'licenceOneOf', - 'languageOneOf', - 'tagsOneOf', - 'tagsAllOf', - 'isLocal', - 'include', - 'skipCount' - ]) - } - - private buildUploadFields (attributes: VideoEdit) { - return omit(attributes, [ 'fixture', 'thumbnailfile', 'previewfile' ]) - } - - private buildUploadAttaches (attributes: VideoEdit) { - const attaches: { [ name: string ]: string } = {} - - for (const key of [ 'thumbnailfile', 'previewfile' ]) { - if (attributes[key]) attaches[key] = buildAbsoluteFixturePath(attributes[key]) - } - - if (attributes.fixture) attaches.videofile = buildAbsoluteFixturePath(attributes.fixture) - - return attaches - } -} diff --git a/shared/extra-utils/videos/videos.ts b/shared/extra-utils/videos/videos.ts deleted file mode 100644 index 2c3464aa8..000000000 --- a/shared/extra-utils/videos/videos.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/no-floating-promises */ - -import { expect } from 'chai' -import { pathExists, readdir } from 'fs-extra' -import { basename, join } from 'path' -import { HttpStatusCode, VideoCaption, VideoDetails } from '@shared/models' -import { waitJobs } from '../server' -import { PeerTubeServer } from '../server/server' -import { VideoEdit } from './videos-command' - -async function checkVideoFilesWereRemoved (options: { - server: PeerTubeServer - video: VideoDetails - captions?: VideoCaption[] - onlyVideoFiles?: boolean // default false -}) { - const { video, server, captions = [], onlyVideoFiles = false } = options - - const webtorrentFiles = video.files || [] - const hlsFiles = video.streamingPlaylists[0]?.files || [] - - const thumbnailName = basename(video.thumbnailPath) - const previewName = basename(video.previewPath) - - const torrentNames = webtorrentFiles.concat(hlsFiles).map(f => basename(f.torrentUrl)) - - const captionNames = captions.map(c => basename(c.captionPath)) - - const webtorrentFilenames = webtorrentFiles.map(f => basename(f.fileUrl)) - const hlsFilenames = hlsFiles.map(f => basename(f.fileUrl)) - - let directories: { [ directory: string ]: string[] } = { - videos: webtorrentFilenames, - redundancy: webtorrentFilenames, - [join('playlists', 'hls')]: hlsFilenames, - [join('redundancy', 'hls')]: hlsFilenames - } - - if (onlyVideoFiles !== true) { - directories = { - ...directories, - - thumbnails: [ thumbnailName ], - previews: [ previewName ], - torrents: torrentNames, - captions: captionNames - } - } - - for (const directory of Object.keys(directories)) { - const directoryPath = server.servers.buildDirectory(directory) - - const directoryExists = await pathExists(directoryPath) - if (directoryExists === false) continue - - const existingFiles = await readdir(directoryPath) - for (const existingFile of existingFiles) { - for (const shouldNotExist of directories[directory]) { - expect(existingFile, `File ${existingFile} should not exist in ${directoryPath}`).to.not.contain(shouldNotExist) - } - } - } -} - -async function saveVideoInServers (servers: PeerTubeServer[], uuid: string) { - for (const server of servers) { - server.store.videoDetails = await server.videos.get({ id: uuid }) - } -} - -function checkUploadVideoParam ( - server: PeerTubeServer, - token: string, - attributes: Partial, - expectedStatus = HttpStatusCode.OK_200, - mode: 'legacy' | 'resumable' = 'legacy' -) { - return mode === 'legacy' - ? server.videos.buildLegacyUpload({ token, attributes, expectedStatus }) - : server.videos.buildResumeUpload({ token, attributes, expectedStatus }) -} - -// serverNumber starts from 1 -async function uploadRandomVideoOnServers ( - servers: PeerTubeServer[], - serverNumber: number, - additionalParams?: VideoEdit & { prefixName?: string } -) { - const server = servers.find(s => s.serverNumber === serverNumber) - const res = await server.videos.randomUpload({ wait: false, additionalParams }) - - await waitJobs(servers) - - return res -} - -// --------------------------------------------------------------------------- - -export { - checkUploadVideoParam, - uploadRandomVideoOnServers, - checkVideoFilesWereRemoved, - saveVideoInServers -} -- cgit v1.2.3