Script para fazer o download de videoaulas no Estratégia
EDIT: AGORA ELE BAIXA TODOS OS VÍDEOS, MESMO QUE UMA AULA POSSUA MAIS DE UM VÍDEO.
Sigam as mesmas instruções contidas nesse post: Script para fazer o download de PDFs no Estratégia
Mas no 5º passo em vez de colarem o código do post, colem o seguinte código abaixo. Ele fará o download de todas as videoaulas contidas em uma determinada disciplina ( todas as videoaulas de ex. Direito Administrativo). Isso é útil para quem quer assisti-las em um momento que não possui Internet.
(function() {
// Função para verificar se a aula está aberta
function checkIfLessonOpened(lessonElement) {
return lessonElement.classList.contains('isOpened');
}
// Função para abrir a aula se ela não estiver aberta
function openLesson(lessonElement) {
return new Promise((resolve) => {
const lessonHeader = lessonElement.querySelector('.Collapse-header');
if (!lessonHeader) {
console.log("Erro: Cabeçalho da aula não encontrado.");
resolve();
return;
}
// Se a aula não estiver aberta, clica para abrir
if (!checkIfLessonOpened(lessonElement)) {
lessonHeader.click();
console.log("Aula aberta.");
} else {
console.log("Aula já está aberta.");
}
// Aguarda 3 segundos para a aula abrir completamente
setTimeout(resolve, 3000);
});
}
// Função para processar vídeos de uma aula
async function processLessonVideos(lessonElement, lessonName) {
// Seleciona todos os botões de vídeo dentro da aula
const videoButtonsNodeList = lessonElement.querySelectorAll('.ListVideos-items-video');
const videoButtons = Array.from(videoButtonsNodeList); // Cria uma cópia estática
if (videoButtons.length === 0) {
console.log(`Nenhum vídeo encontrado na aula "${lessonName}".`);
return [];
}
const videoLinks = [];
// Itera sobre cada botão de vídeo
for (let index = 0; index < videoButtons.length; index++) {
const videoButton = videoButtons[index];
const videoIndexSpan = videoButton.querySelector('.VideoItem-info-index');
const videoIndexText = videoIndexSpan ? videoIndexSpan.textContent.trim() : `Vídeo ${index + 1}`;
console.log(`\nProcessando ${videoIndexText} da aula "${lessonName}"...`);
// Verifica se é o primeiro vídeo
if (index === 0) {
// Para o primeiro vídeo, que já está selecionado
const videoUrl = getVideoSrc(lessonElement);
if (videoUrl) {
videoLinks.push(videoUrl);
await downloadVideo(videoUrl, lessonName, videoIndexText);
} else {
console.log(`Erro: URL do ${videoIndexText} não encontrada.`);
}
continue; // Passa para o próximo vídeo
}
// Para vídeos além do primeiro
// Verifica se o botão já está selecionado
const isSelected = videoButton.querySelector('a').classList.contains('isSelected');
let previousSrc = getVideoSrc(lessonElement);
if (!previousSrc) {
console.log(`Erro: Não foi possível obter o src do vídeo atual na aula "${lessonName}".`);
continue;
}
if (!isSelected) {
// Clica no botão para selecionar o vídeo usando dispatchEvent para simular um clique mais robusto
const anchor = videoButton.querySelector('a');
if (anchor) {
anchor.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
console.log(`Selecionado ${videoIndexText}.`);
} else {
console.log(`Erro: Elemento <a> para ${videoIndexText} não encontrado.`);
continue;
}
// Aguarda até que o src do vídeo seja atualizado usando polling
const videoUrl = await waitForVideoSrcChange(lessonElement, previousSrc, 15000, 500);
if (videoUrl) {
videoLinks.push(videoUrl);
await downloadVideo(videoUrl, lessonName, videoIndexText);
} else {
console.log(`Erro: URL do ${videoIndexText} não encontrada após a seleção.`);
}
} else {
console.log(`${videoIndexText} já está selecionado.`);
// Mesmo que já esteja selecionado, obter o src para download
const videoUrl = getVideoSrc(lessonElement);
if (videoUrl && videoUrl !== previousSrc) {
videoLinks.push(videoUrl);
await downloadVideo(videoUrl, lessonName, videoIndexText);
} else {
console.log(`Erro: URL do ${videoIndexText} não encontrada ou não atualizada.`);
}
}
}
return videoLinks;
}
// Função para aguardar até que o src do vídeo seja atualizado usando polling
function waitForVideoSrcChange(lessonElement, oldSrc, timeout = 15000, interval = 500) {
return new Promise((resolve) => {
const startTime = Date.now();
const checkSrc = () => {
const currentSrc = getVideoSrc(lessonElement);
if (currentSrc && currentSrc !== oldSrc) {
console.log(`Detectado novo src: ${currentSrc}`);
resolve(currentSrc);
} else {
if (Date.now() - startTime >= timeout) {
console.log(`Timeout: src do vídeo não mudou após ${timeout}ms.`);
resolve(null);
} else {
setTimeout(checkSrc, interval);
}
}
};
checkSrc();
});
}
// Função para obter o elemento de vídeo
function getVideoElement(lessonElement) {
return lessonElement.querySelector('video.video-react-video[src^="https://www.estrategiaconcursos.com.br/storage/video/"]');
}
// Função para obter o src do vídeo
function getVideoSrc(lessonElement) {
const videoElement = getVideoElement(lessonElement);
return videoElement ? videoElement.src : null;
}
// Função para baixar o vídeo
async function downloadVideo(videoUrl, lessonName, videoIndexText) {
return new Promise((resolve) => {
// Cria um link temporário para simular o clique de download
const link = document.createElement('a');
link.href = videoUrl;
// Define o nome sugerido para o download
const fileName = `${lessonName} - ${videoIndexText}.mp4`;
link.download = fileName;
// Configura para abrir em nova aba
link.target = '_blank';
// Adiciona o link ao corpo do documento
document.body.appendChild(link);
// Simula o clique no link
link.click();
// Remove o link após o clique
document.body.removeChild(link);
console.log(`${videoIndexText} baixado como: ${fileName}`);
resolve();
});
}
// Função principal para processar todas as aulas uma por uma
async function processLessons() {
const lessons = document.querySelectorAll('.LessonList-item');
if (lessons.length === 0) {
console.log("Nenhuma aula encontrada na página.");
return;
}
let lessonsList = [];
// Itera sobre cada aula
for (let i = 0; i < lessons.length; i++) {
const lesson = lessons[i];
const lessonNameElement = lesson.querySelector('.SectionTitle-no-margin'); // Obtém o nome da aula
const lessonName = lessonNameElement ? lessonNameElement.textContent.trim() : `Aula ${i}`; // Nome da aula, ex: "Aula 00"
console.log(`\nProcessando ${lessonName}...`);
// Abre a aula se necessário
await openLesson(lesson);
// Espera a aula abrir completamente antes de acessar os vídeos
await new Promise(resolve => setTimeout(resolve, 3000)); // Espera 3 segundos para a aula abrir
// Agora processa os vídeos da aula
const videoLinks = await processLessonVideos(lesson, lessonName);
// Adiciona os links dos vídeos à lista de aulas
lessonsList.push({
lessonName,
videoLinks
});
// **Removido: Verificação de downloads concluídos**
// await waitForDownloads(videoLinks);
// **Apenas uma breve espera antes de passar para a próxima aula**
await new Promise(resolve => setTimeout(resolve, 1000)); // Espera 1 segundo entre as aulas
}
// Exibe a lista de aulas e vídeos identificados
console.log("\nLista de Aulas e Vídeos Identificados:");
lessonsList.forEach((lesson, index) => {
console.log(`${index + 1}. ${lesson.lessonName}:`);
lesson.videoLinks.forEach((url, i) => {
console.log(` ${i + 1}. ${url}`);
});
});
console.log("Processamento das aulas concluído!");
}
// Chama a função principal
processLessons();
})();
Obs. 1: que não sou programador e quem criou o código foi o Chat GPT (tive o trabalho de ir tentando prompts corretos até conseguir o que queria), então provavelmente é imperfeito. Quaisquer erros que encontrarem postem aqui explicando que tentarei corrigir, se possível.
Obs. 2: Nosso caro amigo AffectionateCake4830 já melhorou o código mencionado no início do post, como descrito a seguir: Script para fazer o download de PDFs no Estratégia - versão 2.0 então acessem esse tutorial de preferência para baixarem os PDFs.
Obs. 3: Estou tentando fazer com que o código baixe também vídeos em alta qualidade (720) dependendo da escolha do usuário. Por enquanto o código baixa apenas vídeos em 360. Quando (se) eu conseguir fazer isso atualizo o post. Espalhem para que todos possam estudar melhor, por um país melhor.