"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processVideoStudioEdition = void 0;
const tslib_1 = require("tslib");
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const ffmpeg_1 = require("../../../helpers/ffmpeg");
const webtorrent_1 = require("../../../helpers/webtorrent");
const config_1 = require("../../../initializers/config");
const videos_1 = require("../../activitypub/videos");
const paths_1 = require("../../paths");
const default_transcoding_profiles_1 = require("../../transcoding/default-transcoding-profiles");
const user_1 = require("../../user");
const video_1 = require("../../video");
const video_file_1 = require("../../video-file");
const video_path_manager_1 = require("../../video-path-manager");
const video_studio_1 = require("../../video-studio");
const user_2 = require("../../../models/user/user");
const video_2 = require("../../../models/video/video");
const video_file_2 = require("../../../models/video/video-file");
const core_utils_1 = require("../../../../shared/core-utils");
const extra_utils_1 = require("../../../../shared/extra-utils");
const logger_1 = require("../../../helpers/logger");
const job_queue_1 = require("../job-queue");
const lTagsBase = (0, logger_1.loggerTagsFactory)('video-edition');
function processVideoStudioEdition(job) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const payload = job.data;
        const lTags = lTagsBase(payload.videoUUID);
        logger_1.logger.info('Process video studio edition of %s in job %s.', payload.videoUUID, job.id, lTags);
        const video = yield video_2.VideoModel.loadFull(payload.videoUUID);
        if (!video) {
            logger_1.logger.info('Can\'t process job %d, video does not exist.', job.id, lTags);
            return undefined;
        }
        yield checkUserQuotaOrThrow(video, payload);
        const inputFile = video.getMaxQualityFile();
        const editionResultPath = yield video_path_manager_1.VideoPathManager.Instance.makeAvailableVideoFile(inputFile, (originalFilePath) => tslib_1.__awaiter(this, void 0, void 0, function* () {
            let tmpInputFilePath;
            let outputPath;
            for (const task of payload.tasks) {
                const outputFilename = (0, extra_utils_1.buildUUID)() + inputFile.extname;
                outputPath = (0, path_1.join)(config_1.CONFIG.STORAGE.TMP_DIR, outputFilename);
                yield processTask({
                    inputPath: tmpInputFilePath !== null && tmpInputFilePath !== void 0 ? tmpInputFilePath : originalFilePath,
                    video,
                    outputPath,
                    task,
                    lTags
                });
                if (tmpInputFilePath)
                    yield (0, fs_extra_1.remove)(tmpInputFilePath);
                tmpInputFilePath = outputPath;
            }
            return outputPath;
        }));
        logger_1.logger.info('Video edition ended for video %s.', video.uuid, lTags);
        const newFile = yield buildNewFile(video, editionResultPath);
        const outputPath = video_path_manager_1.VideoPathManager.Instance.getFSVideoFileOutputPath(video, newFile);
        yield (0, fs_extra_1.move)(editionResultPath, outputPath);
        yield (0, webtorrent_1.createTorrentAndSetInfoHashFromPath)(video, newFile, outputPath);
        yield removeAllFiles(video, newFile);
        yield newFile.save();
        video.duration = yield (0, extra_utils_1.getVideoStreamDuration)(outputPath);
        yield video.save();
        yield (0, videos_1.federateVideoIfNeeded)(video, false, undefined);
        const user = yield user_2.UserModel.loadByVideoId(video.id);
        yield job_queue_1.JobQueue.Instance.createJob(yield (0, video_1.buildOptimizeOrMergeAudioJob)({ video, videoFile: newFile, user, isNewVideo: false }));
    });
}
exports.processVideoStudioEdition = processVideoStudioEdition;
const taskProcessors = {
    'add-intro': processAddIntroOutro,
    'add-outro': processAddIntroOutro,
    'cut': processCut,
    'add-watermark': processAddWatermark
};
function processTask(options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { video, task } = options;
        logger_1.logger.info('Processing %s task for video %s.', task.name, video.uuid, Object.assign({ task }, options.lTags));
        const processor = taskProcessors[options.task.name];
        if (!process)
            throw new Error('Unknown task ' + task.name);
        return processor(options);
    });
}
function processAddIntroOutro(options) {
    const { task } = options;
    return (0, ffmpeg_1.addIntroOutro)(Object.assign(Object.assign({}, (0, core_utils_1.pick)(options, ['inputPath', 'outputPath'])), { introOutroPath: task.options.file, type: task.name === 'add-intro'
            ? 'intro'
            : 'outro', availableEncoders: default_transcoding_profiles_1.VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), profile: config_1.CONFIG.TRANSCODING.PROFILE }));
}
function processCut(options) {
    const { task } = options;
    return (0, ffmpeg_1.cutVideo)(Object.assign(Object.assign({}, (0, core_utils_1.pick)(options, ['inputPath', 'outputPath'])), { start: task.options.start, end: task.options.end }));
}
function processAddWatermark(options) {
    const { task } = options;
    return (0, ffmpeg_1.addWatermark)(Object.assign(Object.assign({}, (0, core_utils_1.pick)(options, ['inputPath', 'outputPath'])), { watermarkPath: task.options.file, availableEncoders: default_transcoding_profiles_1.VideoTranscodingProfilesManager.Instance.getAvailableEncoders(), profile: config_1.CONFIG.TRANSCODING.PROFILE }));
}
function buildNewFile(video, path) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const videoFile = new video_file_2.VideoFileModel({
            extname: (0, core_utils_1.getLowercaseExtension)(path),
            size: yield (0, extra_utils_1.getFileSize)(path),
            metadata: yield (0, extra_utils_1.buildFileMetadata)(path),
            videoStreamingPlaylistId: null,
            videoId: video.id
        });
        const probe = yield (0, extra_utils_1.ffprobePromise)(path);
        videoFile.fps = yield (0, extra_utils_1.getVideoStreamFPS)(path, probe);
        videoFile.resolution = (yield (0, extra_utils_1.getVideoStreamDimensionsInfo)(path, probe)).resolution;
        videoFile.filename = (0, paths_1.generateWebTorrentVideoFilename)(videoFile.resolution, videoFile.extname);
        return videoFile;
    });
}
function removeAllFiles(video, webTorrentFileException) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        yield (0, video_file_1.removeHLSPlaylist)(video);
        for (const file of video.VideoFiles) {
            if (file.id === webTorrentFileException.id)
                continue;
            yield (0, video_file_1.removeWebTorrentFile)(video, file.id);
        }
    });
}
function checkUserQuotaOrThrow(video, payload) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const user = yield user_2.UserModel.loadByVideoId(video.id);
        const filePathFinder = (i) => payload.tasks[i].options.file;
        const additionalBytes = yield (0, video_studio_1.approximateIntroOutroAdditionalSize)(video, payload.tasks, filePathFinder);
        if ((yield (0, user_1.isAbleToUploadVideo)(user.id, additionalBytes)) === false) {
            throw new Error('Quota exceeded for this user to edit the video');
        }
    });
}
//# sourceMappingURL=video-studio-edition.js.map