"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.YoutubeDLCLI = void 0;
const tslib_1 = require("tslib");
const execa_1 = tslib_1.__importDefault(require("execa"));
const fs_extra_1 = require("fs-extra");
const path_1 = require("path");
const config_1 = require("../../initializers/config");
const logger_1 = require("../logger");
const proxy_1 = require("../proxy");
const requests_1 = require("../requests");
const lTags = (0, logger_1.loggerTagsFactory)('youtube-dl');
const youtubeDLBinaryPath = (0, path_1.join)(config_1.CONFIG.STORAGE.BIN_DIR, config_1.CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE.NAME);
class YoutubeDLCLI {
    static safeGet() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            if (!(yield (0, fs_extra_1.pathExists)(youtubeDLBinaryPath))) {
                yield (0, fs_extra_1.ensureDir)((0, path_1.dirname)(youtubeDLBinaryPath));
                yield this.updateYoutubeDLBinary();
            }
            return new YoutubeDLCLI();
        });
    }
    static updateYoutubeDLBinary() {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const url = config_1.CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE.URL;
            logger_1.logger.info('Updating youtubeDL binary from %s.', url, lTags());
            const gotOptions = { context: { bodyKBLimit: 20000 }, responseType: 'buffer' };
            try {
                let gotResult = yield (0, requests_1.peertubeGot)(url, gotOptions);
                if (!(0, requests_1.isBinaryResponse)(gotResult)) {
                    const json = JSON.parse(gotResult.body.toString());
                    const latest = json.filter(release => release.prerelease === false)[0];
                    if (!latest)
                        throw new Error('Cannot find latest release');
                    const releaseName = config_1.CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE.NAME;
                    const releaseAsset = latest.assets.find(a => a.name === releaseName);
                    if (!releaseAsset)
                        throw new Error(`Cannot find appropriate release with name ${releaseName} in release assets`);
                    gotResult = yield (0, requests_1.peertubeGot)(releaseAsset.browser_download_url, gotOptions);
                }
                if (!(0, requests_1.isBinaryResponse)(gotResult)) {
                    throw new Error('Not a binary response');
                }
                yield (0, fs_extra_1.writeFile)(youtubeDLBinaryPath, gotResult.body);
                logger_1.logger.info('youtube-dl updated %s.', youtubeDLBinaryPath, lTags());
            }
            catch (err) {
                logger_1.logger.error('Cannot update youtube-dl from %s.', url, Object.assign({ err }, lTags()));
            }
        });
    }
    static getYoutubeDLVideoFormat(enabledResolutions, useBestFormat) {
        let result = [];
        if (!useBestFormat) {
            const resolution = enabledResolutions.length === 0
                ? 720
                : Math.max(...enabledResolutions);
            result = [
                `bestvideo[vcodec^=avc1][height=${resolution}]+bestaudio[ext=m4a]`,
                `bestvideo[vcodec!*=av01][vcodec!*=vp9.2][height=${resolution}]+bestaudio`,
                `bestvideo[vcodec^=avc1][height<=${resolution}]+bestaudio[ext=m4a]`
            ];
        }
        return result.concat([
            'bestvideo[vcodec!*=av01][vcodec!*=vp9.2]+bestaudio',
            'best[vcodec!*=av01][vcodec!*=vp9.2]',
            'bestvideo[ext=mp4]+bestaudio[ext=m4a]',
            'best'
        ]).join('/');
    }
    constructor() {
    }
    download(options) {
        let args = options.additionalYoutubeDLArgs || [];
        args = args.concat(['--merge-output-format', 'mp4', '-f', options.format, '-o', options.output]);
        return this.run({
            url: options.url,
            processOptions: options.processOptions,
            timeout: options.timeout,
            args
        });
    }
    getInfo(options) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { url, format, additionalYoutubeDLArgs = [], processOptions } = options;
            const completeArgs = additionalYoutubeDLArgs.concat(['--dump-json', '-f', format]);
            const data = yield this.run({ url, args: completeArgs, processOptions });
            if (!data)
                return undefined;
            const info = data.map(d => JSON.parse(d));
            return info.length === 1
                ? info[0]
                : info;
        });
    }
    getListInfo(options) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const additionalYoutubeDLArgs = ['--skip-download', '--playlist-reverse'];
            if (config_1.CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE.NAME === 'yt-dlp') {
                additionalYoutubeDLArgs.push('--flat-playlist');
            }
            if (options.latestVideosCount !== undefined) {
                additionalYoutubeDLArgs.push('--playlist-end', options.latestVideosCount.toString());
            }
            const result = yield this.getInfo({
                url: options.url,
                format: YoutubeDLCLI.getYoutubeDLVideoFormat([], false),
                processOptions: options.processOptions,
                additionalYoutubeDLArgs
            });
            if (!result)
                return result;
            if (!Array.isArray(result))
                return [result];
            return result;
        });
    }
    getSubs(options) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { url, format, processOptions } = options;
            const args = ['--skip-download', '--all-subs', `--sub-format=${format}`];
            const data = yield this.run({ url, args, processOptions });
            const files = [];
            const skipString = '[info] Writing video subtitles to: ';
            for (let i = 0, len = data.length; i < len; i++) {
                const line = data[i];
                if (line.indexOf(skipString) === 0) {
                    files.push(line.slice(skipString.length));
                }
            }
            return files;
        });
    }
    run(options) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const { url, args, timeout, processOptions } = options;
            let completeArgs = this.wrapWithProxyOptions(args);
            completeArgs = this.wrapWithIPOptions(completeArgs);
            completeArgs = this.wrapWithFFmpegOptions(completeArgs);
            const { PYTHON_PATH } = config_1.CONFIG.IMPORT.VIDEOS.HTTP.YOUTUBE_DL_RELEASE;
            const subProcess = (0, execa_1.default)(PYTHON_PATH, [youtubeDLBinaryPath, ...completeArgs, url], processOptions);
            if (timeout) {
                setTimeout(() => subProcess.cancel(), timeout);
            }
            const output = yield subProcess;
            logger_1.logger.debug('Run youtube-dl command.', Object.assign({ command: output.command }, lTags()));
            return output.stdout
                ? output.stdout.trim().split(/\r?\n/)
                : undefined;
        });
    }
    wrapWithProxyOptions(args) {
        if ((0, proxy_1.isProxyEnabled)()) {
            logger_1.logger.debug('Using proxy %s for YoutubeDL', (0, proxy_1.getProxy)(), lTags());
            return ['--proxy', (0, proxy_1.getProxy)()].concat(args);
        }
        return args;
    }
    wrapWithIPOptions(args) {
        if (config_1.CONFIG.IMPORT.VIDEOS.HTTP.FORCE_IPV4) {
            logger_1.logger.debug('Force ipv4 for YoutubeDL');
            return ['--force-ipv4'].concat(args);
        }
        return args;
    }
    wrapWithFFmpegOptions(args) {
        if (process.env.FFMPEG_PATH) {
            logger_1.logger.debug('Using ffmpeg location %s for YoutubeDL', process.env.FFMPEG_PATH, lTags());
            return ['--ffmpeg-location', process.env.FFMPEG_PATH].concat(args);
        }
        return args;
    }
}
exports.YoutubeDLCLI = YoutubeDLCLI;
//# sourceMappingURL=youtube-dl-cli.js.map