NPTEL-Save-Sourse-Content

Get all content downloads of any nptel course. \n Adds a button on the nav bar to run the script.

目前為 2023-04-23 提交的版本,檢視 最新版本

// ==UserScript==
// @name         NPTEL-Save-Sourse-Content
// @match        https://onlinecourses.nptel.ac.in/*
// @grant        GM_setValue
// @license      MIT
// @description  Get all content downloads of any nptel course. \n Adds a button on the nav bar to run the script. 
// @version      0.2.1
// @namespace    https://gf.qytechs.cn/users/941655
// ==/UserScript==

let courseContentWeeks = [];
const DEBUG = true;

let getContent = async (course) => {
  let ret = null;

  switch (course.type) {
    case "assignment":
    case "material": {
      const body = await (await fetch(course.href)).text();
      const dom = new DOMParser().parseFromString(body, "text/html");
      ret = dom.querySelector('a[target="_blank"]')?.getAttribute("href");
      if (!ret) {
        ret = dom.querySelector('iframe[src^="https://drive"], iframe[src^="https://docs.google.com"]')?.getAttribute("src");
        !ret && DEBUG && console.log("[Error] No link found");
      }
    }
      break;

    case "book":
    case "transcript":
    case "lecture": {
      const body = await (await fetch(course.href)).text();
      const dom = new DOMParser().parseFromString(body, "text/html");
      ret = dom.querySelector('a[target]')?.getAttribute("href");
      !ret && DEBUG && console.log("[Error] No link found");
    }
      break;

    default:
      DEBUG && console.log('UNIMPLEMENTED type', course);
      break;
  }

  DEBUG && console.log(course.title);
  return { ...course, data: ret };
};

let scriptMain = async () => {
  let nodes = document.querySelectorAll(
    "div[id^=unit_navbar] > ul[id^=subunit_navbar]"
  );

  nodes.forEach((el) => {
    const week = [];
    const tags = el.querySelectorAll("li > div > a");
    tags.forEach((tag) => {
      const thing = tag.textContent.toLowerCase();
      if (thing.includes("solution")) {
        week.push({
          href: tag.getAttribute("href"),
          title: tag.textContent,
          type: "assignment",
        });
      } else if (thing.includes("course material")) {
        week.push({
          href: tag.getAttribute("href"),
          title: tag.textContent,
          type: "material",
        });
      } else if (thing.includes("book")) {
        week.push({
          href: tag.getAttribute("href"),
          title: tag.textContent,
          type: "book",
        });
      } else if (thing.includes("transcript")) {
        week.push({
          href: tag.getAttribute("href"),
          title: tag.textContent,
          type: "transcript",
        });
      } else if (thing.includes("lecture material")) {
        week.push({
          href: tag.getAttribute("href"),
          title: tag.textContent,
          type: "lecture",
        });
      } else {
        DEBUG && console.log("UNKNOWN thing", tag.textContent);
      }
    });
    week.length && courseContentWeeks.push(week);
  });

  await courseContents();

};

const courseContents = async () => {
  const promises = [];
  const total = courseContentWeeks.flat().length;

  for (let weekIdx = 0; weekIdx < courseContentWeeks.length; weekIdx++)
    for (let i = 0; i < courseContentWeeks[weekIdx].length; i++)
      promises.push(updateContent(weekIdx, i, total));

  await Promise.all(promises);
}

const updateContent = async (weekIdx, i, total) => {
  const el = courseContentWeeks[weekIdx][i];
  courseContentWeeks[weekIdx][i] = await getContent(el);
  incrementProgress(total);
}

function buildTable(labels, objects, container) {
  const table = document.createElement('table');
  table.style.textAlign = 'center';
  table.style.width = '100%';

  const thead = document.createElement('thead');
  const tbody = document.createElement('tbody');
  const theadTr = document.createElement('tr');

  for (let i = 0; i < labels.length; i++) {
    const theadTh = document.createElement('th');
    theadTh.innerHTML = labels[i].toUpperCase();
    theadTr.appendChild(theadTh);
  }
  thead.appendChild(theadTr);
  table.appendChild(thead);

  for (let j = 0; j < objects.length; j++) {
    const tbodyTr = document.createElement('tr');
    for (let k = 0; k < labels.length; k++) {
      const tbodyTd = document.createElement('td');
      tbodyTd.style.padding = '10px';
      if (objects[j][labels[k]]?.startsWith('http')) {
        const a = document.createElement('a');
        a.href = objects[j][labels[k]];
        a.target = '_blank';
        a.innerHTML = 'Open Link';
        tbodyTd.appendChild(a);
      }
      else
        tbodyTd.innerHTML = objects[j][labels[k]];
      tbodyTr.appendChild(tbodyTd);
    }
    tbody.appendChild(tbodyTr);
  }
  table.appendChild(tbody);

  container.prepend(table);
}

let nav = document.querySelector(".gcb-aux");
let button = document.createElement("button");

const progressDiv = document.createElement("div");
progressDiv.appendChild(document.createTextNode("Please wait..."));
const progress = document.createElement('span')
progressDiv.appendChild(progress);

const setProgress = (val) => {
  progress.innerText = `${val.toPrecision(2)}%`;
};

const incrementProgress = (total) => {
  const val = parseFloat(progress.innerText.replace('%', ''));
  setProgress(val + 100 / total);
};

setProgress(0);
progressDiv.style.display = "none";

button.innerHTML = "Run Script";



button.onclick = async () => {
  console.log("scriptMain");
  progressDiv.style.display = "block";
  await scriptMain();
  progressDiv.style.display = "none";

  console.table(courseContentWeeks.flat());
  buildTable(['title', 'type', 'data'], courseContentWeeks.flat(), document.getElementById('gcb-main-body'));

  console.log(courseContentWeeks.flat().map((el) => el.type === 'lecture' && el.data));
};

nav.appendChild(button);
nav.appendChild(progressDiv)

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址