"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processVideoTranscoding = void 0;
const tslib_1 = require("tslib");
const video_1 = require("../../video");
const video_path_manager_1 = require("../../video-path-manager");
const video_state_1 = require("../../video-state");
const user_1 = require("../../../models/user/user");
const video_job_info_1 = require("../../../models/video/video-job-info");
const core_utils_1 = require("../../../../shared/core-utils");
const database_utils_1 = require("../../../helpers/database-utils");
const ffprobe_utils_1 = require("../../../helpers/ffprobe-utils");
const logger_1 = require("../../../helpers/logger");
const config_1 = require("../../../initializers/config");
const video_2 = require("../../../models/video/video");
const video_transcoding_1 = require("../../transcoding/video-transcoding");
const handlers = {
    'new-resolution-to-hls': handleHLSJob,
    'new-resolution-to-webtorrent': handleNewWebTorrentResolutionJob,
    'merge-audio-to-webtorrent': handleWebTorrentMergeAudioJob,
    'optimize-to-webtorrent': handleWebTorrentOptimizeJob
};
const lTags = (0, logger_1.loggerTagsFactory)('transcoding');
function processVideoTranscoding(job) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const payload = job.data;
        logger_1.logger.info('Processing transcoding job %d.', job.id, lTags(payload.videoUUID));
        const video = yield video_2.VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoUUID);
        if (!video) {
            logger_1.logger.info('Do not process job %d, video does not exist.', job.id, lTags(payload.videoUUID));
            return undefined;
        }
        const user = yield user_1.UserModel.loadByChannelActorId(video.VideoChannel.actorId);
        const handler = handlers[payload.type];
        if (!handler) {
            yield (0, video_state_1.moveToFailedTranscodingState)(video);
            yield video_job_info_1.VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode');
            throw new Error('Cannot find transcoding handler for ' + payload.type);
        }
        try {
            yield handler(job, payload, video, user);
        }
        catch (error) {
            yield (0, video_state_1.moveToFailedTranscodingState)(video);
            yield video_job_info_1.VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode');
            throw error;
        }
        return video;
    });
}
exports.processVideoTranscoding = processVideoTranscoding;
function handleHLSJob(job, payload, video, user) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        logger_1.logger.info('Handling HLS transcoding job for %s.', video.uuid, lTags(video.uuid));
        const videoFileInput = payload.copyCodecs
            ? video.getWebTorrentFile(payload.resolution)
            : video.getMaxQualityFile();
        const videoOrStreamingPlaylist = videoFileInput.getVideoOrStreamingPlaylist();
        yield video_path_manager_1.VideoPathManager.Instance.makeAvailableVideoFile(videoFileInput.withVideoOrPlaylist(videoOrStreamingPlaylist), videoInputPath => {
            return (0, video_transcoding_1.generateHlsPlaylistResolution)({
                video,
                videoInputPath,
                resolution: payload.resolution,
                copyCodecs: payload.copyCodecs,
                isPortraitMode: payload.isPortraitMode || false,
                job
            });
        });
        logger_1.logger.info('HLS transcoding job for %s ended.', video.uuid, lTags(video.uuid));
        yield onHlsPlaylistGeneration(video, user, payload);
    });
}
function handleNewWebTorrentResolutionJob(job, payload, video, user) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        logger_1.logger.info('Handling WebTorrent transcoding job for %s.', video.uuid, lTags(video.uuid));
        yield (0, video_transcoding_1.transcodeNewWebTorrentResolution)(video, payload.resolution, payload.isPortraitMode || false, job);
        logger_1.logger.info('WebTorrent transcoding job for %s ended.', video.uuid, lTags(video.uuid));
        yield onNewWebTorrentFileResolution(video, user, payload);
    });
}
function handleWebTorrentMergeAudioJob(job, payload, video, user) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        logger_1.logger.info('Handling merge audio transcoding job for %s.', video.uuid, lTags(video.uuid));
        yield (0, video_transcoding_1.mergeAudioVideofile)(video, payload.resolution, job);
        logger_1.logger.info('Merge audio transcoding job for %s ended.', video.uuid, lTags(video.uuid));
        yield onVideoFirstWebTorrentTranscoding(video, payload, 'video', user);
    });
}
function handleWebTorrentOptimizeJob(job, payload, video, user) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        logger_1.logger.info('Handling optimize transcoding job for %s.', video.uuid, lTags(video.uuid));
        const { transcodeType } = yield (0, video_transcoding_1.optimizeOriginalVideofile)(video, video.getMaxQualityFile(), job);
        logger_1.logger.info('Optimize transcoding job for %s ended.', video.uuid, lTags(video.uuid));
        yield onVideoFirstWebTorrentTranscoding(video, payload, transcodeType, user);
    });
}
function onHlsPlaylistGeneration(video, user, payload) {
    var _a;
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        if (payload.isMaxQuality && payload.autoDeleteWebTorrentIfNeeded && config_1.CONFIG.TRANSCODING.WEBTORRENT.ENABLED === false) {
            for (const file of video.VideoFiles) {
                yield video.removeWebTorrentFileAndTorrent(file);
                yield file.destroy();
            }
            video.VideoFiles = [];
            yield createLowerResolutionsJobs({
                video,
                user,
                videoFileResolution: payload.resolution,
                isPortraitMode: payload.isPortraitMode,
                hasAudio: payload.hasAudio,
                isNewVideo: (_a = payload.isNewVideo) !== null && _a !== void 0 ? _a : true,
                type: 'hls'
            });
        }
        yield video_job_info_1.VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode');
        yield (0, database_utils_1.retryTransactionWrapper)(video_state_1.moveToNextState, video, payload.isNewVideo);
    });
}
function onVideoFirstWebTorrentTranscoding(videoArg, payload, transcodeType, user) {
    var _a;
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const { resolution, isPortraitMode, audioStream } = yield videoArg.getMaxQualityFileInfo();
        const videoDatabase = yield video_2.VideoModel.loadAndPopulateAccountAndServerAndTags(videoArg.uuid);
        if (!videoDatabase)
            return undefined;
        const originalFileHLSPayload = Object.assign(Object.assign({}, payload), { isPortraitMode, hasAudio: !!audioStream, resolution: videoDatabase.getMaxQualityFile().resolution, copyCodecs: transcodeType !== 'quick-transcode', isMaxQuality: true });
        const hasHls = yield createHlsJobIfEnabled(user, originalFileHLSPayload);
        const hasNewResolutions = yield createLowerResolutionsJobs({
            video: videoDatabase,
            user,
            videoFileResolution: resolution,
            hasAudio: !!audioStream,
            isPortraitMode,
            type: 'webtorrent',
            isNewVideo: (_a = payload.isNewVideo) !== null && _a !== void 0 ? _a : true
        });
        yield video_job_info_1.VideoJobInfoModel.decrease(videoDatabase.uuid, 'pendingTranscode');
        if (!hasHls && !hasNewResolutions) {
            yield (0, database_utils_1.retryTransactionWrapper)(video_state_1.moveToNextState, videoDatabase, payload.isNewVideo);
        }
    });
}
function onNewWebTorrentFileResolution(video, user, payload) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        if (payload.createHLSIfNeeded) {
            yield createHlsJobIfEnabled(user, Object.assign({ hasAudio: true, copyCodecs: true, isMaxQuality: false }, payload));
        }
        yield video_job_info_1.VideoJobInfoModel.decrease(video.uuid, 'pendingTranscode');
        yield (0, database_utils_1.retryTransactionWrapper)(video_state_1.moveToNextState, video, payload.isNewVideo);
    });
}
function createHlsJobIfEnabled(user, payload) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        if (!payload || config_1.CONFIG.TRANSCODING.ENABLED !== true || config_1.CONFIG.TRANSCODING.HLS.ENABLED !== true)
            return false;
        const jobOptions = {
            priority: yield (0, video_1.getTranscodingJobPriority)(user)
        };
        const hlsTranscodingPayload = Object.assign({ type: 'new-resolution-to-hls', autoDeleteWebTorrentIfNeeded: true }, (0, core_utils_1.pick)(payload, ['videoUUID', 'resolution', 'isPortraitMode', 'copyCodecs', 'isMaxQuality', 'isNewVideo', 'hasAudio']));
        yield (0, video_1.addTranscodingJob)(hlsTranscodingPayload, jobOptions);
        return true;
    });
}
function createLowerResolutionsJobs(options) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const { video, user, videoFileResolution, isPortraitMode, isNewVideo, hasAudio, type } = options;
        const resolutionsEnabled = (0, ffprobe_utils_1.computeLowerResolutionsToTranscode)(videoFileResolution, 'vod');
        const resolutionCreated = [];
        for (const resolution of resolutionsEnabled) {
            if (resolution === 0 && hasAudio === false)
                continue;
            let dataInput;
            if (config_1.CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') {
                dataInput = {
                    type: 'new-resolution-to-webtorrent',
                    videoUUID: video.uuid,
                    resolution,
                    isPortraitMode,
                    hasAudio,
                    createHLSIfNeeded: true,
                    isNewVideo
                };
                resolutionCreated.push('webtorrent-' + resolution);
            }
            if (config_1.CONFIG.TRANSCODING.HLS.ENABLED && type === 'hls') {
                dataInput = {
                    type: 'new-resolution-to-hls',
                    videoUUID: video.uuid,
                    resolution,
                    isPortraitMode,
                    hasAudio,
                    copyCodecs: false,
                    isMaxQuality: false,
                    autoDeleteWebTorrentIfNeeded: true,
                    isNewVideo
                };
                resolutionCreated.push('hls-' + resolution);
            }
            if (!dataInput)
                continue;
            const jobOptions = {
                priority: yield (0, video_1.getTranscodingJobPriority)(user)
            };
            yield (0, video_1.addTranscodingJob)(dataInput, jobOptions);
        }
        if (resolutionCreated.length === 0) {
            logger_1.logger.info('No transcoding jobs created for video %s (no resolutions).', video.uuid, lTags(video.uuid));
            return false;
        }
        logger_1.logger.info('New resolutions %s transcoding jobs created for video %s and origin file resolution of %d.', type, video.uuid, videoFileResolution, Object.assign({ resolutionCreated }, lTags(video.uuid)));
        return true;
    });
}
//# sourceMappingURL=video-transcoding.js.map