vivo-dl
Version:
download videos from vivo.sx
119 lines (118 loc) • 5.21 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.vivodl = void 0;
const fs = __importStar(require("fs"));
const node_fetch_1 = __importDefault(require("node-fetch"));
const puppeteer_extra_plugin_stealth_1 = __importDefault(require("puppeteer-extra-plugin-stealth"));
const cheerio_1 = __importDefault(require("cheerio"));
const video_1 = require("./models/video");
const puppeteer_extra_1 = __importDefault(require("puppeteer-extra"));
const mkdirp_1 = __importDefault(require("mkdirp"));
async function vivodl(destinationFolder = "", vivoUrls = []) {
let videos = [];
try {
if (!fs.existsSync(destinationFolder)) {
await mkdirp_1.default(destinationFolder);
}
videos = await fetchVideoSources(vivoUrls);
await downloadVideos(videos, destinationFolder);
fs.writeFileSync(destinationFolder + "/resources.json", JSON.stringify(videos, null, 2));
}
catch (error) {
console.error(`❌ It seems like something went wrong: ${error}`);
}
return videos;
}
exports.vivodl = vivodl;
async function fetchVideoSources(vivoUrls) {
console.log("▶ Fetching all video sources");
const videos = [];
puppeteer_extra_1.default.use(puppeteer_extra_plugin_stealth_1.default());
const browser = await puppeteer_extra_1.default.launch({ headless: true });
const context = await browser.createIncognitoBrowserContext();
await Promise.all(vivoUrls.map(async (vivoUrl) => {
const page = await context.newPage();
intercept(page);
if (!vivoUrl.includes("vivo.sx")) {
console.log(`⚠ Skipping ${vivoUrl} because it is not a valid vivo url.`);
return;
}
await page.goto(vivoUrl);
try {
await Promise.all([
page.waitForSelector("div.stream-content", { timeout: 60000 }),
page.waitForSelector("source", { timeout: 60000 }),
]);
}
catch (error) {
console.log(`⚠ Skipping ${vivoUrl} because the video could not be found.`);
return;
}
const $ = cheerio_1.default.load(await page.evaluate(() => document.body.innerHTML));
await page.close();
const extractedName = $("div.stream-content").attr("data-name");
const extractedUrl = $("source").attr("src");
videos.push(new video_1.Video(extractedName, extractedUrl, vivoUrl));
}));
await browser.close();
console.log(`✔ Fetched ${videos.length} video sources`);
return videos;
}
async function downloadVideos(videos, destinationFolder = "") {
if (destinationFolder == "") {
console.log("✨ Fetched the video URIs}");
return;
}
console.log("▶ Starting video downloads");
destinationFolder = stripPath(destinationFolder);
let downloadedVideos = 0;
await Promise.all(videos.map(async (video) => {
console.log(`▶ Downloading video ${video.filename} from ${video.vivoUrl}`);
const dest = `${destinationFolder}/${video.filename}`;
const response = await node_fetch_1.default(video.videoUrl);
try {
await fs.promises.writeFile(dest, await response.buffer());
console.log(`✔ Downloaded video (${++downloadedVideos}/${videos.length}) ${video.filename} from ${video.vivoUrl}`);
}
catch (error) {
console.error(`❌ Failed to download video (${++downloadedVideos}/${videos.length}) ${video.filename} from ${video.vivoUrl}: ${error}`);
}
}));
console.log(`✨ Downloaded ${downloadedVideos} of ${videos.length} videos to ${destinationFolder}`);
}
function stripPath(path) {
return path.replace(/\/$/, "");
}
async function intercept(page) {
await page.setRequestInterception(true);
page.on('request', request => {
if (request.resourceType() === 'font' || request.resourceType() === 'image' || request.resourceType() === 'stylesheet') {
request.abort();
return;
}
request.continue();
return;
});
}