"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.videoImportsRouter = void 0;
const tslib_1 = require("tslib");
const express_1 = tslib_1.__importDefault(require("express"));
const fs_extra_1 = require("fs-extra");
const magnet_uri_1 = require("magnet-uri");
const parse_torrent_1 = tslib_1.__importDefault(require("parse-torrent"));
const path_1 = require("path");
const video_pre_import_1 = require("../../../lib/video-pre-import");
const audit_logger_1 = require("../../../helpers/audit-logger");
const misc_1 = require("../../../helpers/custom-validators/misc");
const express_utils_1 = require("../../../helpers/express-utils");
const logger_1 = require("../../../helpers/logger");
const utils_1 = require("../../../helpers/utils");
const config_1 = require("../../../initializers/config");
const constants_1 = require("../../../initializers/constants");
const job_queue_1 = require("../../../lib/job-queue/job-queue");
const thumbnail_1 = require("../../../lib/thumbnail");
const middlewares_1 = require("../../../middlewares");
const auditLogger = (0, audit_logger_1.auditLoggerFactory)('video-imports');
const videoImportsRouter = express_1.default.Router();
exports.videoImportsRouter = videoImportsRouter;
const reqVideoFileImport = (0, express_utils_1.createReqFiles)(['thumbnailfile', 'previewfile', 'torrentfile'], Object.assign(Object.assign({}, constants_1.MIMETYPES.TORRENT.MIMETYPE_EXT), constants_1.MIMETYPES.IMAGE.MIMETYPE_EXT));
videoImportsRouter.post('/imports', middlewares_1.authenticate, reqVideoFileImport, (0, middlewares_1.asyncMiddleware)(middlewares_1.videoImportAddValidator), (0, middlewares_1.asyncRetryTransactionMiddleware)(handleVideoImport));
videoImportsRouter.post('/imports/:id/cancel', middlewares_1.authenticate, (0, middlewares_1.asyncMiddleware)(middlewares_1.videoImportCancelValidator), (0, middlewares_1.asyncRetryTransactionMiddleware)(cancelVideoImport));
videoImportsRouter.delete('/imports/:id', middlewares_1.authenticate, (0, middlewares_1.asyncMiddleware)(middlewares_1.videoImportDeleteValidator), (0, middlewares_1.asyncRetryTransactionMiddleware)(deleteVideoImport));
function deleteVideoImport(req, res) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const videoImport = res.locals.videoImport;
        yield videoImport.destroy();
        return res.sendStatus(204);
    });
}
function cancelVideoImport(req, res) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const videoImport = res.locals.videoImport;
        videoImport.state = 5;
        yield videoImport.save();
        return res.sendStatus(204);
    });
}
function handleVideoImport(req, res) {
    var _a, _b;
    if (req.body.targetUrl)
        return handleYoutubeDlImport(req, res);
    const file = (_b = (_a = req.files) === null || _a === void 0 ? void 0 : _a['torrentfile']) === null || _b === void 0 ? void 0 : _b[0];
    if (req.body.magnetUri || file)
        return handleTorrentImport(req, res, file);
}
function handleTorrentImport(req, res, torrentfile) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const body = req.body;
        const user = res.locals.oauth.token.User;
        let videoName;
        let torrentName;
        let magnetUri;
        if (torrentfile) {
            const result = yield processTorrentOrAbortRequest(req, res, torrentfile);
            if (!result)
                return;
            videoName = result.name;
            torrentName = result.torrentName;
        }
        else {
            const result = processMagnetURI(body);
            magnetUri = result.magnetUri;
            videoName = result.name;
        }
        const video = yield (0, video_pre_import_1.buildVideoFromImport)({
            channelId: res.locals.videoChannel.id,
            importData: { name: videoName },
            importDataOverride: body,
            importType: 'torrent'
        });
        const thumbnailModel = yield processThumbnail(req, video);
        const previewModel = yield processPreview(req, video);
        const videoImport = yield (0, video_pre_import_1.insertFromImportIntoDB)({
            video,
            thumbnailModel,
            previewModel,
            videoChannel: res.locals.videoChannel,
            tags: body.tags || undefined,
            user,
            videoImportAttributes: {
                magnetUri,
                torrentName,
                state: 1,
                userId: user.id
            }
        });
        const payload = {
            type: torrentfile
                ? 'torrent-file'
                : 'magnet-uri',
            videoImportId: videoImport.id,
            preventException: false
        };
        yield job_queue_1.JobQueue.Instance.createJob({ type: 'video-import', payload });
        auditLogger.create((0, audit_logger_1.getAuditIdFromRes)(res), new audit_logger_1.VideoImportAuditView(videoImport.toFormattedJSON()));
        return res.json(videoImport.toFormattedJSON()).end();
    });
}
function statusFromYtDlImportError(err) {
    switch (err.code) {
        case video_pre_import_1.YoutubeDlImportError.CODE.NOT_ONLY_UNICAST_URL:
            return 403;
        case video_pre_import_1.YoutubeDlImportError.CODE.FETCH_ERROR:
            return 400;
        default:
            return 500;
    }
}
function handleYoutubeDlImport(req, res) {
    var _a, _b, _c, _d;
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const body = req.body;
        const targetUrl = body.targetUrl;
        const user = res.locals.oauth.token.User;
        try {
            const { job, videoImport } = yield (0, video_pre_import_1.buildYoutubeDLImport)({
                targetUrl,
                channel: res.locals.videoChannel,
                importDataOverride: body,
                thumbnailFilePath: (_b = (_a = req.files) === null || _a === void 0 ? void 0 : _a['thumbnailfile']) === null || _b === void 0 ? void 0 : _b[0].path,
                previewFilePath: (_d = (_c = req.files) === null || _c === void 0 ? void 0 : _c['previewfile']) === null || _d === void 0 ? void 0 : _d[0].path,
                user
            });
            yield job_queue_1.JobQueue.Instance.createJob(job);
            auditLogger.create((0, audit_logger_1.getAuditIdFromRes)(res), new audit_logger_1.VideoImportAuditView(videoImport.toFormattedJSON()));
            return res.json(videoImport.toFormattedJSON()).end();
        }
        catch (err) {
            logger_1.logger.error('An error occurred while importing the video %s. ', targetUrl, { err });
            return res.fail({
                message: err.message,
                status: statusFromYtDlImportError(err),
                data: {
                    targetUrl
                }
            });
        }
    });
}
function processThumbnail(req, video) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const thumbnailField = req.files ? req.files['thumbnailfile'] : undefined;
        if (thumbnailField) {
            const thumbnailPhysicalFile = thumbnailField[0];
            return (0, thumbnail_1.updateVideoMiniatureFromExisting)({
                inputPath: thumbnailPhysicalFile.path,
                video,
                type: 1,
                automaticallyGenerated: false
            });
        }
        return undefined;
    });
}
function processPreview(req, video) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const previewField = req.files ? req.files['previewfile'] : undefined;
        if (previewField) {
            const previewPhysicalFile = previewField[0];
            return (0, thumbnail_1.updateVideoMiniatureFromExisting)({
                inputPath: previewPhysicalFile.path,
                video,
                type: 2,
                automaticallyGenerated: false
            });
        }
        return undefined;
    });
}
function processTorrentOrAbortRequest(req, res, torrentfile) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const torrentName = torrentfile.originalname;
        const newTorrentPath = (0, path_1.join)(config_1.CONFIG.STORAGE.TORRENTS_DIR, (0, utils_1.getSecureTorrentName)(torrentName));
        yield (0, fs_extra_1.move)(torrentfile.path, newTorrentPath, { overwrite: true });
        torrentfile.path = newTorrentPath;
        const buf = yield (0, fs_extra_1.readFile)(torrentfile.path);
        const parsedTorrent = (0, parse_torrent_1.default)(buf);
        if (parsedTorrent.files.length !== 1) {
            (0, express_utils_1.cleanUpReqFiles)(req);
            res.fail({
                type: "incorrect_files_in_torrent",
                message: 'Torrents with only 1 file are supported.'
            });
            return undefined;
        }
        return {
            name: extractNameFromArray(parsedTorrent.name),
            torrentName
        };
    });
}
function processMagnetURI(body) {
    const magnetUri = body.magnetUri;
    const parsed = (0, magnet_uri_1.decode)(magnetUri);
    return {
        name: extractNameFromArray(parsed.name),
        magnetUri
    };
}
function extractNameFromArray(name) {
    return (0, misc_1.isArray)(name) ? name[0] : name;
}
//# sourceMappingURL=import.js.map