Reewrite #1
22
package.json
22
package.json
@ -5,21 +5,17 @@
|
||||
"type": "module",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cookie": "^0.5.0",
|
||||
"get-video-duration": "^4.1.0",
|
||||
"got": "^13.0.0",
|
||||
"jsdom": "^22.1.0",
|
||||
"mongodb": "^6.2.0",
|
||||
"neste": "^3.0.0",
|
||||
"telegraf": "^4.15.0",
|
||||
"turndown": "^7.1.2"
|
||||
"cookie": "^0.6.0",
|
||||
"got": "^14.0.0",
|
||||
"jsdom": "^23.0.1",
|
||||
"mongodb": "^6.3.0",
|
||||
"neste": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cookie": "^0.5.3",
|
||||
"@types/jsdom": "^21.1.4",
|
||||
"@types/node": "^20.8.10",
|
||||
"@types/turndown": "^5.0.3",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/jsdom": "^21.1.6",
|
||||
"@types/node": "^20.10.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { ColaborareadRequest } from "./lib/colabora_req.js";
|
||||
|
||||
export default Get;
|
||||
export async function Get(gotDom: ColaborareadRequest["gotDom"], semestre: string) {
|
||||
const dashboard = new URL("https://www.colaboraread.com.br/aluno/dashboard/index"); dashboard.searchParams.set("matriculaId", semestre);
|
||||
const { url: pageUrl, jsdoc } = (await gotDom(dashboard));
|
||||
const { window: { document } } = jsdoc;
|
||||
|
||||
return Array.from(document.querySelectorAll("#navbar-content-aluno-pda > ul > li")).reduce<{ title: string; id: string }[]>((acc, e) => {
|
||||
if (!(e.querySelector("table > tbody > tr > td:nth-child(1) > a"))) return acc;
|
||||
const a = e.querySelector("table > tbody > tr > td:nth-child(1) > a");
|
||||
const title = a.getAttribute("title").trim(), pageHref = (new URL(a.getAttribute("href"), pageUrl)).searchParams.get("ofertaDisciplinaId")
|
||||
if (pageHref) acc.push({ title, id: pageHref });
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
@ -3,6 +3,7 @@ import { Got } from "./lib/colabora_req.js";
|
||||
export enum AulasType {
|
||||
"Portfólio" = "1",
|
||||
"Tele Aula" = "2",
|
||||
"Leitura" = "3",
|
||||
"Web Aula" = "4",
|
||||
"Avaliação Virtual" = "6",
|
||||
"Prova Presencial" = "13",
|
||||
@ -13,10 +14,28 @@ export enum AulasType {
|
||||
"Atividade Diagnóstica" = "23",
|
||||
"Atividade de Aprendizagem" = "24",
|
||||
"Prova Prática Presencial" = "26",
|
||||
"Engajamento AVA" = "27",
|
||||
"Desafio Nota Máxima" = "28",
|
||||
"Acelere Sua Carreira" = "31",
|
||||
};
|
||||
|
||||
export const AulasTypeIDs: readonly (AulasType[number])[] = Object.freeze([
|
||||
"1",
|
||||
"2",
|
||||
"4",
|
||||
"6",
|
||||
"13",
|
||||
"14",
|
||||
"16",
|
||||
"17",
|
||||
"22",
|
||||
"23",
|
||||
"24",
|
||||
"26",
|
||||
"28",
|
||||
"31"
|
||||
]);
|
||||
|
||||
export type Boletim = {
|
||||
detalheBoletimDto: {
|
||||
detalheEngajamentoDtoList: {
|
||||
@ -82,7 +101,6 @@ export async function Get(got: Got, matricula: string, disciplina: string) {
|
||||
boletimUrl.searchParams.set("ofertaDisciplinaId", disciplina);
|
||||
const body: Boletim = (await got<Boletim>(boletimUrl, { responseType: "json" })).body;
|
||||
|
||||
|
||||
const media = body.map(body => {
|
||||
const Acts = Object.keys(body.detalheBoletimDto.detalheDisciplinarDtoList).map<{type: AulasType, pontos: number}>((type: AulasType) => {
|
||||
if (type === AulasType["Avaliação Virtual"]) {
|
||||
|
160
src/dashboard.ts
160
src/dashboard.ts
@ -1,8 +1,12 @@
|
||||
import path from "path";
|
||||
import util from "node:util"
|
||||
import { ColaborareadRequest } from "./lib/colabora_req.js";
|
||||
import { AulasType, AulasTypeIDs } from "./boletim.js";
|
||||
import { writeFile } from "fs/promises";
|
||||
|
||||
export default Get;
|
||||
export async function Get(gotdom: ColaborareadRequest["gotDom"]) {
|
||||
const { window: { document } } = (await gotdom("https://www.colaboraread.com.br/index/index")).jsdoc;
|
||||
export async function Get(colareq: ColaborareadRequest) {
|
||||
const { window: { document } } = (await colareq.gotDom("https://www.colaboraread.com.br/index/index")).jsdoc;
|
||||
document.querySelector("#navbar-content-aluno-cursos > div > div:nth-child(1) > div")
|
||||
return Array.from(document.querySelectorAll("#navbar-content-aluno-cursos > div > div")).reduce<{ name: string; semestres: {semestreID: string; title: string;}[] }[]>((acc, e) => {
|
||||
if (!(e.querySelector("div > div:nth-child(2) > h3"))) return acc;
|
||||
@ -11,13 +15,159 @@ export async function Get(gotdom: ColaborareadRequest["gotDom"]) {
|
||||
// Title
|
||||
const title = (e.querySelector("div > div:nth-child(2) > h3") as HTMLHeadingElement).getAttribute("title");
|
||||
|
||||
// Push to array
|
||||
acc.push({
|
||||
// retornar os cursos
|
||||
return acc.concat({
|
||||
name: title,
|
||||
semestres: Array.from<HTMLOptionElement>(e.querySelectorAll("div > div:nth-child(1) > div:nth-child(3) > form > div:nth-child(1) > select > option")).map(({ value, innerText, innerHTML }) => ({ semestreID: value, title: (innerText||innerHTML).trim() })).reverse()
|
||||
});
|
||||
}, []);
|
||||
}
|
||||
|
||||
// retornar os cursos
|
||||
export namespace Aulas {
|
||||
export async function Get(colareq: ColaborareadRequest, semestre: string) {
|
||||
const dashboard = new URL("https://www.colaboraread.com.br/aluno/dashboard/index"); dashboard.searchParams.set("matriculaId", semestre);
|
||||
await colareq.gotDom(dashboard);
|
||||
const { url: pageUrl, jsdoc } = (await colareq.gotDom(dashboard));
|
||||
const { window: { document } } = jsdoc;
|
||||
console.log(pageUrl.toString());
|
||||
await writeFile(String().concat("./tmp_data/aulas_", semestre, ".html"), jsdoc.serialize())
|
||||
|
||||
return Array.from(document.querySelectorAll("#navbar-content-aluno-pda > ul > li")).reduce<{ title: string; id: string }[]>((acc, e) => {
|
||||
if (!(e.querySelector("table > tbody > tr > td:nth-child(1) > a"))) return acc;
|
||||
const a = e.querySelector("table > tbody > tr > td:nth-child(1) > a");
|
||||
const title = a.getAttribute("title").trim(), pageHref = (new URL(a.getAttribute("href"), pageUrl)).searchParams.get("ofertaDisciplinaId")
|
||||
if (pageHref) return acc.concat({ title, id: pageHref });
|
||||
return acc;
|
||||
}, []);
|
||||
}
|
||||
};
|
||||
|
||||
export namespace Atividades {
|
||||
export interface Atividade {
|
||||
type: string;
|
||||
title: string;
|
||||
id: string;
|
||||
};
|
||||
|
||||
export interface Teleaula extends Atividade {
|
||||
type: "Teleaula";
|
||||
files: {
|
||||
title: string;
|
||||
url: URL;
|
||||
}[];
|
||||
videos: {
|
||||
codigoMidia: string;
|
||||
mediaType: string;
|
||||
atividadeOfertaId: number;
|
||||
exemplarId?: string;
|
||||
mdsUrl?: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface Portfolio extends Atividade {
|
||||
type: "Portfólio";
|
||||
Dates: Record<string, Date[]>;
|
||||
files: {
|
||||
title: string;
|
||||
url: URL;
|
||||
}[];
|
||||
historico?: {
|
||||
type: string;
|
||||
text: string;
|
||||
description?: string;
|
||||
date?: Date;
|
||||
}[];
|
||||
}
|
||||
|
||||
export async function Get(colareq: ColaborareadRequest, semestre: string, id: string): Promise<(Atividade|Teleaula|Portfolio)[]> {
|
||||
const indexURL = new URL(path.posix.join("/aluno/timeline/index", semestre).concat("?ofertaDisciplinaId=", id), "https://www.colaboraread.com.br");
|
||||
const { jsdoc, url: pageUrl } = (await colareq.gotDom(indexURL));
|
||||
const { window: { document } } = jsdoc;
|
||||
|
||||
return Promise.all(Array.from(document.querySelectorAll("#js-activities-container > li")).map(async act => {
|
||||
console.log(Array.from(act.classList.values()));
|
||||
if (AulasTypeIDs.some(s => act.classList.contains(String().concat("tipo-", s)))) {
|
||||
const type = AulasTypeIDs.find(s => act.classList.contains(String().concat("tipo-", s)));
|
||||
if (type === AulasType["Portfólio"]) {
|
||||
const portUrl = new URL(act.querySelector("div.timeline-panel > div > div.timeline-body > div.row.form-group > div > a").getAttribute("href"), pageUrl);
|
||||
const { jsdoc } = await colareq.gotDom(portUrl);
|
||||
const { window: { document } } = jsdoc;
|
||||
|
||||
const port: Portfolio = Object.create({});
|
||||
port.type = "Portfólio";
|
||||
port.id = portUrl.searchParams.get("atividadeDisciplinaId");
|
||||
port.title = act.querySelector("div.timeline-panel > div > h4 > small").textContent.trim();
|
||||
|
||||
port.files = Array.from(document.querySelectorAll("#conteudo > div > div:nth-child(2) > div.col-md-4 > div > div.panel-body > ul:nth-child(4) > li")).map(s => s.querySelector("a")).filter(Boolean).map(s => ({
|
||||
title: s.getAttribute("name")||s.getAttribute("title"),
|
||||
url: new URL(s.getAttribute("href"), portUrl)
|
||||
}));
|
||||
|
||||
const daySplit = (s: string) => { const [day, month, yeat] = s.split("/"); return String().concat(month, "/", day, "/", yeat); }
|
||||
port.Dates = {};
|
||||
Array.from(document.querySelectorAll("#conteudo > div > div:nth-child(2) > div.col-md-4 > div:nth-child(1) > div.panel-body > ul:nth-child(1) > li")).forEach((doc): any => {
|
||||
const text = doc.textContent.trim();
|
||||
let index: number;
|
||||
if ((index = text.indexOf(":")) >= 0) {
|
||||
const key = text.slice(0, index).trim();
|
||||
const [ day1, hor1,, day2, hor2 ] = text.slice(index+1).trim().split(/\s+/);
|
||||
if (!day2) return port.Dates[key] = [ new Date(String().concat(daySplit(day1), " ", hor1, " GMT-3")) ];
|
||||
port.Dates[key] = [ new Date(String().concat(daySplit(day1), " ", hor1, " GMT-3")), new Date(String().concat(daySplit(day2), " ", hor2, " GMT-3")) ];
|
||||
}
|
||||
}, []);
|
||||
|
||||
if (document.querySelector("#conteudo > div > div:nth-child(2) > div.col-md-8 > div")) {
|
||||
port.historico = [];
|
||||
Array.from(document.querySelectorAll("#conteudo > div > div:nth-child(2) > div.col-md-8 > div")).forEach(a => {
|
||||
if (a.querySelector("div:nth-child(1) > h5")) {
|
||||
const dd = new Date(daySplit(a.querySelector("div:nth-child(1) > h5 > abbr").getAttribute("title")));
|
||||
const status = a.querySelector("div:nth-child(1) > h5 > span");
|
||||
|
||||
port.historico.push({
|
||||
type: status.textContent.trim(),
|
||||
date: dd,
|
||||
description: status.getAttribute("title"),
|
||||
text: a.querySelector("div:nth-child(2) > p").textContent.trim(),
|
||||
});
|
||||
return;
|
||||
}
|
||||
port.historico.push({
|
||||
type: String(a.querySelector("div:nth-child(1) > p:nth-child(1) > span")?.textContent).trim(),
|
||||
date: new Date(daySplit(a.querySelector("div:nth-child(1) > p:nth-child(2) > abbr").getAttribute("title").trim())),
|
||||
text: String(a.querySelector("div:nth-child(2) > p")?.textContent).trim(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return port;
|
||||
} else if (type === AulasType["Leitura"]) {
|
||||
await writeFile(String().concat("./tmp_data/", type, ".html"), act.innerHTML);
|
||||
} else if (type === AulasType["Conteúdo Web"]) {
|
||||
} else if (type === AulasType["Tele Aula"]) {
|
||||
const teleUrl = new URL(act.querySelector("div.timeline-panel > div > div.timeline-body > div.row.form-group > div > a").getAttribute("href"), pageUrl);
|
||||
const { jsdoc } = await colareq.gotDom(teleUrl);
|
||||
const { window: { document } } = jsdoc;
|
||||
const tele: Teleaula = Object.create({});
|
||||
tele.type = "Teleaula";
|
||||
tele.id = teleUrl.searchParams.get("atividadeDisciplinaId");
|
||||
tele.title = act.querySelector("div.timeline-panel > div > h4 > small").textContent.trim();
|
||||
tele.files = Array.from(act.querySelectorAll("div.timeline-panel > div > div.timeline-body > ul > li")).map<HTMLAnchorElement>(s => s.querySelector("small > a")).filter(Boolean).map(s => ({ title: s.getAttribute("title")||s.getAttribute("name"), url: new URL(s.href, pageUrl) }));
|
||||
|
||||
const ids = Array.from(document.querySelectorAll("#conteudo > div > div > div.col-md-8.panel.mb-30 > div:nth-child(2) > div > div > div")).map(div => {
|
||||
/** codigoMidia, mediaType, matriculaId, atividadeOfertaId, exemplarId */
|
||||
let media: { codigoMidia: string, mediaType: string, atividadeOfertaId: number, exemplarId?: string };
|
||||
// @ts-ignore
|
||||
function playVideosMensagem(codigoMidia, mediaType, _matriculaId, atividadeOfertaId, exemplarId) { media = {codigoMidia, mediaType, atividadeOfertaId, exemplarId}; }
|
||||
eval(div.querySelector("div > div > a").getAttribute("onclick"));
|
||||
return media;
|
||||
});
|
||||
|
||||
tele.videos = ids.map(s => ({ ...s, mdsUrl: util.format("https://mdstrm.com/video/%s.json", s.codigoMidia), }));
|
||||
return tele;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
})).then(s => s.filter(Boolean));
|
||||
}
|
||||
};
|
26
src/index.ts
26
src/index.ts
@ -1,10 +1,9 @@
|
||||
import "./lib/db_connect.js";
|
||||
import request, { ColaborareadRequest } from "./lib/colabora_req.js";
|
||||
import { encrypt } from "./lib/password.js";
|
||||
import neste from "neste";
|
||||
import boletim from "./boletim.js";
|
||||
import Dashboard from "./dashboard.js";
|
||||
import Atividade from "./atividades.js";
|
||||
import Dashboard, { Atividades, Aulas } from "./dashboard.js";
|
||||
import request, { ColaborareadRequest } from "./lib/colabora_req.js";
|
||||
import "./lib/db_connect.js";
|
||||
import { encrypt } from "./lib/password.js";
|
||||
|
||||
const app = neste();
|
||||
// Listen HTTP Server
|
||||
@ -43,6 +42,7 @@ app.use(async (req, res, next): Promise<any> => {
|
||||
]
|
||||
});
|
||||
}
|
||||
} else if (req.headers.authorization.toLowerCase().startsWith("bearer ")) {
|
||||
} else if (req.headers.authorization.toLowerCase().startsWith("token ")) {
|
||||
req.headers.authorization.slice(6).trim();
|
||||
}
|
||||
@ -59,20 +59,14 @@ app.use(async (req, res, next): Promise<any> => {
|
||||
});
|
||||
|
||||
// Semestres
|
||||
app.get("/", async (req, res) => res.json(await Dashboard(req.Got.gotDom)));
|
||||
|
||||
// Aulas
|
||||
app.get("/aula/:semestre", async (req, res) => res.json(await Atividade(req.Got.gotDom, req.params.semestre)));
|
||||
app.get("/aula/:semestre/:displina");
|
||||
app.get("/", async (req, res) => res.json(await Dashboard(req.Got)));
|
||||
|
||||
// Boletim
|
||||
app.get("/boletim", async (req, res) => {
|
||||
res.json(await Promise.all((await Dashboard(req.Got.gotDom)).map(async s => ({ name: s.name, semestres: await Promise.all(s.semestres.map(async s => await Promise.all((await Atividade(req.Got.gotDom, s.semestreID)).map(async s => ({ title: s.title, boletim: await boletim(req.Got.got, req.params.semestre, s.id), }))))) }))));
|
||||
});
|
||||
app.get("/boletim/:semestre", async (req, res) => {
|
||||
res.json(await Promise.all((await Atividade(req.Got.gotDom, req.params.semestre)).map(async s => ({ title: s.title, boletim: await boletim(req.Got.got, req.params.semestre, s.id), }))));
|
||||
});
|
||||
app.get("/boletim/:semestre/:displina", async (req, res) => {
|
||||
const bot = await boletim(req.Got.got, req.params.semestre, req.params.displina);
|
||||
return res.json(bot);
|
||||
});
|
||||
|
||||
// Aulas
|
||||
app.get("/aula/:semestre", async (req, res) => res.json(await Aulas.Get(req.Got, req.params.semestre)));
|
||||
app.get("/aula/:semestre/:displina", async (req, res) => res.json(await Atividades.Get(req.Got, req.params.semestre, req.params.displina)));
|
@ -1,11 +1,11 @@
|
||||
import { decrypt } from "./password.js";
|
||||
import { JSDOM } from "jsdom";
|
||||
import cookie from "cookie";
|
||||
import got, { Got, OptionsOfBufferResponseBody, OptionsOfTextResponseBody } from "got";
|
||||
import { IncomingHttpHeaders } from "http";
|
||||
import { JSDOM } from "jsdom";
|
||||
import { decrypt } from "./password.js";
|
||||
|
||||
export type { Got };
|
||||
export { remoteRequest };
|
||||
export type { Got };
|
||||
|
||||
export interface ColaborareadRequest {
|
||||
cookies: Map<string, Record<string, string>>;
|
||||
@ -31,27 +31,31 @@ export default async function remoteRequest(username: string, password: string):
|
||||
throwHttpErrors: true,
|
||||
encoding: "utf8",
|
||||
headers: {
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36",
|
||||
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||
"sec-ch-ua": "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"",
|
||||
"accept-language": "pt-BR,pt;q=0.9,en;q=0.8,en-US;q=0.7",
|
||||
"cache-control": "no-cache",
|
||||
"pragma": "no-cache",
|
||||
"sec-ch-ua": "\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"",
|
||||
"sec-ch-ua-mobile": "?0",
|
||||
"sec-ch-ua-platform": "\"Windows\"",
|
||||
"sec-fetch-site": "none",
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-user": "?1",
|
||||
"sec-fetch-dest": "document",
|
||||
// "accept-encoding": "gzip, deflate, br",
|
||||
"accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7"
|
||||
"sec-fetch-mode": "navigate",
|
||||
"sec-fetch-site": "same-origin",
|
||||
"sec-fetch-user": "?1",
|
||||
"upgrade-insecure-requests": "1",
|
||||
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537."
|
||||
},
|
||||
cookieJar: {
|
||||
async getCookieString(url: string) { const data = localCookie.get((new URL(url)).hostname)||{}; return Object.keys(data).reduce<string>((acc, k) => acc.concat(";", k, "=", data[k]), ""); },
|
||||
async getCookieString(url: string) {
|
||||
const data = localCookie.get((new URL(url)).hostname)||{};
|
||||
return Object.keys(data).reduce<string>((acc, k) => acc.concat(";", k, "=", data[k]), "");
|
||||
},
|
||||
async setCookie(rawCookie: string, url: string) {
|
||||
const host = (new URL(url)).hostname
|
||||
if (!(localCookie.has(host))) localCookie.set(host, {});
|
||||
const cookieData = cookie.parse(rawCookie);
|
||||
([ "Expires", "Max-Age", "Domain", "Path", "Secure", "HttpOnly", "SameSite" ]).forEach(k => delete cookieData[k]);
|
||||
for (const k in cookieData) {
|
||||
if (([ "expires", "max-age", "domain", "path", "secure", "httponly", "samesite" ]).includes(k.toLowerCase())) continue;
|
||||
if (cookieData[k]) localCookie.get(host)[k] = cookieData[k];
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user