"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.processVideoTranscoding = void 0;
const tslib_1 = require("tslib");
const hooks_1 = require("../../plugins/hooks");
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 ffmpeg_1 = require("../../../helpers/ffmpeg");
const logger_1 = require("../../../helpers/logger");
const config_1 = require("../../../initializers/config");
const video_2 = require("../../../models/video/video");
const transcoding_1 = require("../../transcoding/transcoding");
const job_queue_1 = require("../job-queue");
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 tslib_1.__awaiter(this, void 0, void 0, function* () {
        const payload = job.data;
        logger_1.logger.info('Processing transcoding job %s.', job.id, lTags(payload.videoUUID));
        const video = yield video_2.VideoModel.loadFull(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 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();
        const inputFileMutexReleaser = yield video_path_manager_1.VideoPathManager.Instance.lockFiles(video.uuid);
        try {
            yield videoFileInput.getVideo().reload();
            yield video_path_manager_1.VideoPathManager.Instance.makeAvailableVideoFile(videoFileInput.withVideoOrPlaylist(videoOrStreamingPlaylist), videoInputPath => {
                return (0, transcoding_1.generateHlsPlaylistResolution)({
                    video,
                    videoInputPath,
                    inputFileMutexReleaser,
                    resolution: payload.resolution,
                    copyCodecs: payload.copyCodecs,
                    job
                });
            });
        }
        finally {
            inputFileMutexReleaser();
        }
        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 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, transcoding_1.transcodeNewWebTorrentResolution)({ video, resolution: payload.resolution, 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 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, transcoding_1.mergeAudioVideofile)({ video, resolution: 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 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, transcoding_1.optimizeOriginalVideofile)({ video, inputVideoFile: 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 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.removeWebTorrentFile(file);
                yield file.destroy();
            }
            video.VideoFiles = [];
            yield createLowerResolutionsJobs({
                video,
                user,
                videoFileResolution: payload.resolution,
                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, isNewVideo: payload.isNewVideo });
    });
}
function onVideoFirstWebTorrentTranscoding(videoArg, payload, transcodeType, user) {
    var _a;
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const mutexReleaser = yield video_path_manager_1.VideoPathManager.Instance.lockFiles(videoArg.uuid);
        try {
            const videoDatabase = yield video_2.VideoModel.loadFull(videoArg.uuid);
            if (!videoDatabase)
                return undefined;
            const { resolution, audioStream } = yield videoDatabase.probeMaxQualityFile();
            const originalFileHLSPayload = Object.assign(Object.assign({}, payload), { 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,
                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, { video: videoDatabase, isNewVideo: payload.isNewVideo });
            }
        }
        finally {
            mutexReleaser();
        }
    });
}
function onNewWebTorrentFileResolution(video, user, payload) {
    return 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, isNewVideo: payload.isNewVideo });
    });
}
function createHlsJobIfEnabled(user, payload) {
    return 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', 'copyCodecs', 'isMaxQuality', 'isNewVideo', 'hasAudio']));
        yield job_queue_1.JobQueue.Instance.createJob(yield (0, video_1.buildTranscodingJob)(hlsTranscodingPayload, jobOptions));
        return true;
    });
}
function createLowerResolutionsJobs(options) {
    return tslib_1.__awaiter(this, void 0, void 0, function* () {
        const { video, user, videoFileResolution, isNewVideo, hasAudio, type } = options;
        const resolutionsEnabled = yield hooks_1.Hooks.wrapObject((0, ffmpeg_1.computeResolutionsToTranscode)({ input: videoFileResolution, type: 'vod', includeInput: false, strictLower: true, hasAudio }), 'filter:transcoding.auto.resolutions-to-transcode.result', options);
        const resolutionCreated = [];
        for (const resolution of resolutionsEnabled) {
            let dataInput;
            if (config_1.CONFIG.TRANSCODING.WEBTORRENT.ENABLED && type === 'webtorrent') {
                dataInput = {
                    type: 'new-resolution-to-webtorrent',
                    videoUUID: video.uuid,
                    resolution,
                    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,
                    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 job_queue_1.JobQueue.Instance.createJob(yield (0, video_1.buildTranscodingJob)(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