"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateRouter = void 0;
const tslib_1 = require("tslib");
const express_1 = (0, tslib_1.__importDefault)(require("express"));
const webtorrent_1 = require("../../../helpers/webtorrent");
const share_1 = require("../../../lib/activitypub/share");
const video_1 = require("../../../lib/video");
const doc_1 = require("../../../middlewares/doc");
const audit_logger_1 = require("../../../helpers/audit-logger");
const database_utils_1 = require("../../../helpers/database-utils");
const express_utils_1 = require("../../../helpers/express-utils");
const logger_1 = require("../../../helpers/logger");
const config_1 = require("../../../initializers/config");
const constants_1 = require("../../../initializers/constants");
const database_1 = require("../../../initializers/database");
const videos_1 = require("../../../lib/activitypub/videos");
const notifier_1 = require("../../../lib/notifier");
const hooks_1 = require("../../../lib/plugins/hooks");
const video_blacklist_1 = require("../../../lib/video-blacklist");
const middlewares_1 = require("../../../middlewares");
const schedule_video_update_1 = require("../../../models/video/schedule-video-update");
const video_2 = require("../../../models/video/video");
const lTags = (0, logger_1.loggerTagsFactory)('api', 'video');
const auditLogger = (0, audit_logger_1.auditLoggerFactory)('videos');
const updateRouter = express_1.default.Router();
exports.updateRouter = updateRouter;
const reqVideoFileUpdate = (0, express_utils_1.createReqFiles)(['thumbnailfile', 'previewfile'], constants_1.MIMETYPES.IMAGE.MIMETYPE_EXT, {
    thumbnailfile: config_1.CONFIG.STORAGE.TMP_DIR,
    previewfile: config_1.CONFIG.STORAGE.TMP_DIR
});
updateRouter.put('/:id', (0, doc_1.openapiOperationDoc)({ operationId: 'putVideo' }), middlewares_1.authenticate, reqVideoFileUpdate, (0, middlewares_1.asyncMiddleware)(middlewares_1.videosUpdateValidator), (0, middlewares_1.asyncRetryTransactionMiddleware)(updateVideo));
function updateVideo(req, res) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const videoFromReq = res.locals.videoAll;
        const videoFieldsSave = videoFromReq.toJSON();
        const oldVideoAuditView = new audit_logger_1.VideoAuditView(videoFromReq.toFormattedDetailsJSON());
        const videoInfoToUpdate = req.body;
        const wasConfidentialVideo = videoFromReq.isConfidential();
        const hadPrivacyForFederation = videoFromReq.hasPrivacyForFederation();
        const [thumbnailModel, previewModel] = yield (0, video_1.buildVideoThumbnailsFromReq)({
            video: videoFromReq,
            files: req.files,
            fallback: () => Promise.resolve(undefined),
            automaticallyGenerated: false
        });
        try {
            const { videoInstanceUpdated, isNewVideo } = yield database_1.sequelizeTypescript.transaction((t) => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
                const video = yield video_2.VideoModel.loadAndPopulateAccountAndServerAndTags(videoFromReq.id, t);
                const sequelizeOptions = { transaction: t };
                const oldVideoChannel = video.VideoChannel;
                const keysToUpdate = [
                    'name',
                    'category',
                    'licence',
                    'language',
                    'nsfw',
                    'waitTranscoding',
                    'support',
                    'description',
                    'commentsEnabled',
                    'downloadEnabled'
                ];
                for (const key of keysToUpdate) {
                    if (videoInfoToUpdate[key] !== undefined)
                        video.set(key, videoInfoToUpdate[key]);
                }
                if (videoInfoToUpdate.originallyPublishedAt !== undefined && videoInfoToUpdate.originallyPublishedAt !== null) {
                    video.originallyPublishedAt = new Date(videoInfoToUpdate.originallyPublishedAt);
                }
                let isNewVideo = false;
                if (videoInfoToUpdate.privacy !== undefined) {
                    isNewVideo = yield updateVideoPrivacy({ videoInstance: video, videoInfoToUpdate, hadPrivacyForFederation, transaction: t });
                }
                if (!video.changed()) {
                    yield video.setAsRefreshed(t);
                }
                const videoInstanceUpdated = yield video.save(sequelizeOptions);
                if (thumbnailModel)
                    yield videoInstanceUpdated.addAndSaveThumbnail(thumbnailModel, t);
                if (previewModel)
                    yield videoInstanceUpdated.addAndSaveThumbnail(previewModel, t);
                if (videoInfoToUpdate.tags !== undefined) {
                    yield (0, video_1.setVideoTags)({ video: videoInstanceUpdated, tags: videoInfoToUpdate.tags, transaction: t });
                }
                if (res.locals.videoChannel && videoInstanceUpdated.channelId !== res.locals.videoChannel.id) {
                    yield videoInstanceUpdated.$set('VideoChannel', res.locals.videoChannel, { transaction: t });
                    videoInstanceUpdated.VideoChannel = res.locals.videoChannel;
                    if (hadPrivacyForFederation === true)
                        yield (0, share_1.changeVideoChannelShare)(videoInstanceUpdated, oldVideoChannel, t);
                }
                yield updateSchedule(videoInstanceUpdated, videoInfoToUpdate, t);
                yield (0, video_blacklist_1.autoBlacklistVideoIfNeeded)({
                    video: videoInstanceUpdated,
                    user: res.locals.oauth.token.User,
                    isRemote: false,
                    isNew: false,
                    transaction: t
                });
                auditLogger.update((0, audit_logger_1.getAuditIdFromRes)(res), new audit_logger_1.VideoAuditView(videoInstanceUpdated.toFormattedDetailsJSON()), oldVideoAuditView);
                logger_1.logger.info('Video with name %s and uuid %s updated.', video.name, video.uuid, lTags(video.uuid));
                return { videoInstanceUpdated, isNewVideo };
            }));
            if (videoInfoToUpdate.name)
                yield updateTorrentsMetadata(videoInstanceUpdated);
            yield database_1.sequelizeTypescript.transaction(t => (0, videos_1.federateVideoIfNeeded)(videoInstanceUpdated, isNewVideo, t));
            if (wasConfidentialVideo)
                notifier_1.Notifier.Instance.notifyOnNewVideoIfNeeded(videoInstanceUpdated);
            hooks_1.Hooks.runAction('action:api.video.updated', { video: videoInstanceUpdated, body: req.body, req, res });
        }
        catch (err) {
            (0, database_utils_1.resetSequelizeInstance)(videoFromReq, videoFieldsSave);
            throw err;
        }
        return res.type('json')
            .status(204)
            .end();
    });
}
function updateVideoPrivacy(options) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        const { videoInstance, videoInfoToUpdate, hadPrivacyForFederation, transaction } = options;
        const isNewVideo = videoInstance.isNewVideo(videoInfoToUpdate.privacy);
        const newPrivacy = parseInt(videoInfoToUpdate.privacy.toString(), 10);
        videoInstance.setPrivacy(newPrivacy);
        if (hadPrivacyForFederation && !videoInstance.hasPrivacyForFederation()) {
            yield video_2.VideoModel.sendDelete(videoInstance, { transaction });
        }
        return isNewVideo;
    });
}
function updateSchedule(videoInstance, videoInfoToUpdate, transaction) {
    if (videoInfoToUpdate.scheduleUpdate) {
        return schedule_video_update_1.ScheduleVideoUpdateModel.upsert({
            videoId: videoInstance.id,
            updateAt: new Date(videoInfoToUpdate.scheduleUpdate.updateAt),
            privacy: videoInfoToUpdate.scheduleUpdate.privacy || null
        }, { transaction });
    }
    else if (videoInfoToUpdate.scheduleUpdate === null) {
        return schedule_video_update_1.ScheduleVideoUpdateModel.deleteByVideoId(videoInstance.id, transaction);
    }
}
function updateTorrentsMetadata(video) {
    return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
        for (const file of (video.VideoFiles || [])) {
            yield (0, webtorrent_1.updateTorrentMetadata)(video, file);
            yield file.save();
        }
        const hls = video.getHLSPlaylist();
        if (!hls)
            return;
        for (const file of (hls.VideoFiles || [])) {
            yield (0, webtorrent_1.updateTorrentMetadata)(hls, file);
            yield file.save();
        }
    });
}
//# sourceMappingURL=update.js.map