mirror of
https://cdm-project.com/Download-Tools/udemy-downloader.git
synced 2025-04-29 19:44:26 +02:00
Merge pull request #180 from runtlb64/master
Add functionality to parse coding assignments
This commit is contained in:
commit
eb7189178d
118
coding_assignment_template.html
Normal file
118
coding_assignment_template.html
Normal file
@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Coding Assignment</title>
|
||||
|
||||
<style>
|
||||
body {
|
||||
font-family: sf pro text, -apple-system, BlinkMacSystemFont, Roboto,
|
||||
segoe ui, Helvetica, Arial, sans-serif, apple color emoji,
|
||||
segoe ui emoji, segoe ui symbol;
|
||||
font-weight: 400;
|
||||
line-height: 22.4px;
|
||||
font-size: 16px;
|
||||
}
|
||||
p, ul, ol {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-weight: bold;
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
max-width: none;
|
||||
}
|
||||
.code-snippet {
|
||||
background-color: #fff;
|
||||
border: 1px solid #d1d7dc;
|
||||
color: #b4690e;
|
||||
font-size: 90%;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
.code-block {
|
||||
background-color: #fff;
|
||||
color: #b4690e;
|
||||
font-size: 90%;
|
||||
}
|
||||
.black-block {
|
||||
color: #000000;
|
||||
}
|
||||
.italic-text {
|
||||
font-style: italic;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body onload="main()">
|
||||
<h1 id="coding-title"></h1>
|
||||
<div>
|
||||
<h2>Instructions</h2>
|
||||
<div id="coding-instructions"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Test(s)</h2>
|
||||
<div id="coding-tests"></div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>Solution(s)</h2>
|
||||
<div id="coding-solutions"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const quizData = __data_placeholder__;
|
||||
|
||||
function renderCodeList(rootElement, codeList, className, titlePrefix) {
|
||||
for (var i = 0; i < codeList.length; i++) {
|
||||
var elem = codeList[i];
|
||||
var jsElem = document.createElement("div");
|
||||
jsElem.className = className;
|
||||
var jsElemTitle = document.createElement("h3");
|
||||
jsElemTitle.innerHTML = titlePrefix + " " + (i + 1);
|
||||
var jsElemBody = document.createElement("code");
|
||||
jsElemBody.className = "code-block black-block";
|
||||
jsElemBody.innerHTML = "<pre>" + elem.content + "</pre>";
|
||||
jsElem.appendChild(jsElemTitle);
|
||||
jsElem.appendChild(jsElemBody);
|
||||
rootElement.appendChild(jsElem);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
// display the assignment
|
||||
var codingTitle = document.getElementById("coding-title");
|
||||
codingTitle.innerHTML = quizData.title;
|
||||
|
||||
var codingInstructions = document.getElementById("coding-instructions");
|
||||
if (quizData.hasInstructions) {
|
||||
codingInstructions.innerHTML = quizData.instructions;
|
||||
} else {
|
||||
codingInstructions.innerHTML = "<span class=\"italic-text\">" + quizData.instructions
|
||||
+ "</span>";
|
||||
}
|
||||
|
||||
// display the test(s)
|
||||
var codingTests = document.getElementById("coding-tests");
|
||||
if (!quizData.hasTests) {
|
||||
codingTests.innerHTML = "<span class=\"italic-text\">" + quizData.tests + "</span>";
|
||||
} else {
|
||||
renderCodeList(codingTests, quizData.tests, "coding-test", "Test");
|
||||
}
|
||||
|
||||
|
||||
// display the solution(s)
|
||||
var codingSolutions = document.getElementById("coding-solutions");
|
||||
if (!quizData.hasSolutions) {
|
||||
codingSolutions.innerHTML = "<span class=\"italic-text\">" + quizData.solutions + "</span>";
|
||||
} else {
|
||||
renderCodeList(codingSolutions, quizData.solutions, "coding-solution", "Solution");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
68
main.py
68
main.py
@ -385,6 +385,38 @@ class Udemy:
|
||||
sys.exit(1)
|
||||
else:
|
||||
return resp.get("results")
|
||||
|
||||
def _get_elem_value_or_none(self, elem, key):
|
||||
return elem[key] if elem and key in elem else "(None)"
|
||||
|
||||
def _get_quiz_with_info(self, quiz_id):
|
||||
resp = { "_class": None, "_type": None, "contents": None }
|
||||
quiz_json = self._get_quiz(quiz_id)
|
||||
is_only_one = len(quiz_json) == 1 and quiz_json[0]["_class"] == "assessment"
|
||||
is_coding_assignment = quiz_json[0]["assessment_type"] == "coding-problem"
|
||||
|
||||
resp["_class"] = quiz_json[0]["_class"]
|
||||
|
||||
if is_only_one and is_coding_assignment:
|
||||
assignment = quiz_json[0]
|
||||
prompt = assignment["prompt"]
|
||||
|
||||
resp["_type"] = assignment["assessment_type"]
|
||||
|
||||
resp["contents"] = {
|
||||
"instructions": self._get_elem_value_or_none(prompt, "instructions"),
|
||||
"tests": self._get_elem_value_or_none(prompt, "test_files"),
|
||||
"solutions": self._get_elem_value_or_none(prompt, "solution_files"),
|
||||
}
|
||||
|
||||
resp["hasInstructions"] = False if resp["contents"]["instructions"] == "(None)" else True
|
||||
resp["hasTests"] = False if isinstance(resp["contents"]["tests"], str) else True
|
||||
resp["hasSolutions"] = False if isinstance(resp["contents"]["solutions"], str) else True
|
||||
else: # Normal quiz
|
||||
resp["_type"] = "normal-quiz"
|
||||
resp["contents"] = quiz_json
|
||||
|
||||
return resp
|
||||
|
||||
def _extract_supplementary_assets(self, supp_assets, lecture_counter):
|
||||
_temp = []
|
||||
@ -1606,18 +1638,50 @@ def process_lecture(lecture, lecture_path, lecture_file_name, chapter_dir):
|
||||
|
||||
|
||||
def process_quiz(udemy: Udemy, lecture, chapter_dir):
|
||||
quiz = udemy._get_quiz_with_info(lecture.get("id"))
|
||||
if quiz["_type"] == "coding-problem":
|
||||
process_coding_assignment(quiz, lecture, chapter_dir)
|
||||
else: # Normal quiz
|
||||
process_normal_quiz(quiz, lecture, chapter_dir)
|
||||
|
||||
|
||||
def process_normal_quiz(quiz, lecture, chapter_dir):
|
||||
lecture_title = lecture.get("lecture_title")
|
||||
lecture_index = lecture.get("lecture_index")
|
||||
lecture_file_name = sanitize_filename(lecture_title + ".html")
|
||||
lecture_path = os.path.join(chapter_dir, lecture_file_name)
|
||||
|
||||
logger.info(f" > Processing quiz {lecture_index}")
|
||||
questions = udemy._get_quiz(lecture.get("id"))
|
||||
|
||||
with open("quiz_template.html", "r") as f:
|
||||
html = f.read()
|
||||
quiz_data = {
|
||||
"pass_percent": lecture.get("data").get("pass_percent"),
|
||||
"questions": questions,
|
||||
"questions": quiz["contents"],
|
||||
}
|
||||
html = html.replace("__data_placeholder__", json.dumps(quiz_data))
|
||||
with open(lecture_path, "w") as f:
|
||||
f.write(html)
|
||||
|
||||
|
||||
def process_coding_assignment(quiz, lecture, chapter_dir):
|
||||
lecture_title = lecture.get("lecture_title")
|
||||
lecture_index = lecture.get("lecture_index")
|
||||
lecture_file_name = sanitize_filename(lecture_title + ".html")
|
||||
lecture_path = os.path.join(chapter_dir, lecture_file_name)
|
||||
|
||||
logger.info(f" > Processing quiz {lecture_index} (coding assignment)")
|
||||
|
||||
with open("coding_assignment_template.html", "r") as f:
|
||||
html = f.read()
|
||||
quiz_data = {
|
||||
"title": lecture_title,
|
||||
"hasInstructions": quiz["hasInstructions"],
|
||||
"hasTests": quiz["hasTests"],
|
||||
"hasSolutions": quiz["hasSolutions"],
|
||||
"instructions": quiz["contents"]["instructions"],
|
||||
"tests": quiz["contents"]["tests"],
|
||||
"solutions": quiz["contents"]["solutions"],
|
||||
}
|
||||
html = html.replace("__data_placeholder__", json.dumps(quiz_data))
|
||||
with open(lecture_path, "w") as f:
|
||||
|
Loading…
x
Reference in New Issue
Block a user