diff --git a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts index 3aae24732..23bd5ef76 100644 --- a/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts +++ b/client/src/app/+videos/+video-edit/video-add-components/video-import-torrent.component.ts @@ -5,7 +5,7 @@ import { scrollToTop } from '@app/helpers' import { FormValidatorService } from '@app/shared/shared-forms' import { VideoCaptionService, VideoEdit, VideoImportService, VideoService } from '@app/shared/shared-main' import { LoadingBarService } from '@ngx-loading-bar/core' -import { VideoPrivacy, VideoUpdate } from '@shared/models' +import { ServerErrorCode, VideoPrivacy, VideoUpdate } from '@shared/models' import { hydrateFormFromVideo } from '../shared/video-edit-utils' import { VideoSend } from './video-send' @@ -113,7 +113,13 @@ export class VideoImportTorrentComponent extends VideoSend implements OnInit, Af this.loadingBar.useRef().complete() this.isImportingVideo = false this.firstStepError.emit() - this.notifier.error(err.message) + + let message = err.message + if (err.body?.code === ServerErrorCode.INCORRECT_FILES_IN_TORRENT) { + message = $localize`Torrents with only 1 file are supported.` + } + + this.notifier.error(message) } ) } diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index 37fd42b90..4ed58f978 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts @@ -16,13 +16,13 @@ import { MVideoWithBlacklistLight } from '@server/types/models' import { MVideoImport, MVideoImportFormattable } from '@server/types/models/video/video-import' -import { VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '../../../../shared' +import { ServerErrorCode, VideoImportCreate, VideoImportState, VideoPrivacy, VideoState } from '../../../../shared' import { HttpStatusCode } from '../../../../shared/core-utils/miscs/http-error-codes' import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger' import { moveAndProcessCaptionFile } from '../../../helpers/captions-utils' import { isArray } from '../../../helpers/custom-validators/misc' -import { createReqFiles } from '../../../helpers/express-utils' +import { cleanUpReqFiles, createReqFiles } from '../../../helpers/express-utils' import { logger } from '../../../helpers/logger' import { getSecureTorrentName } from '../../../helpers/utils' import { YoutubeDL, YoutubeDLInfo } from '../../../helpers/youtube-dl' @@ -86,13 +86,23 @@ async function addTorrentImport (req: express.Request, res: express.Response, to // Rename the torrent to a secured name const newTorrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, getSecureTorrentName(torrentName)) - await move(torrentfile.path, newTorrentPath) + await move(torrentfile.path, newTorrentPath, { overwrite: true }) torrentfile.path = newTorrentPath const buf = await readFile(torrentfile.path) - const parsedTorrent = parseTorrent(buf) + const parsedTorrent = parseTorrent(buf) as parseTorrent.Instance - videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name as string + if (parsedTorrent.files.length !== 1) { + cleanUpReqFiles(req) + + return res.status(HttpStatusCode.BAD_REQUEST_400) + .json({ + code: ServerErrorCode.INCORRECT_FILES_IN_TORRENT, + error: 'Torrents with only 1 file are supported.' + }) + } + + videoName = isArray(parsedTorrent.name) ? parsedTorrent.name[0] : parsedTorrent.name } else { magnetUri = body.magnetUri diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index c53af3861..d0643ff26 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts @@ -47,14 +47,12 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ cleanUpReqFiles(req) return res.status(HttpStatusCode.CONFLICT_409) .json({ error: 'HTTP import is not enabled on this instance.' }) - .end() } if (CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED !== true && (req.body.magnetUri || torrentFile)) { cleanUpReqFiles(req) return res.status(HttpStatusCode.CONFLICT_409) .json({ error: 'Torrent/magnet URI import is not enabled on this instance.' }) - .end() } if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req) @@ -65,7 +63,6 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ return res.status(HttpStatusCode.BAD_REQUEST_400) .json({ error: 'Should have a magnetUri or a targetUrl or a torrent file.' }) - .end() } if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req) diff --git a/shared/models/server/server-error-code.enum.ts b/shared/models/server/server-error-code.enum.ts index c02b0e6c7..d17d958be 100644 --- a/shared/models/server/server-error-code.enum.ts +++ b/shared/models/server/server-error-code.enum.ts @@ -2,4 +2,5 @@ export const enum ServerErrorCode { DOES_NOT_RESPECT_FOLLOW_CONSTRAINTS = 1, MAX_INSTANCE_LIVES_LIMIT_REACHED = 2, MAX_USER_LIVES_LIMIT_REACHED = 3, + INCORRECT_FILES_IN_TORRENT = 4 }