public function videoRecommendationsAction($scope = 'all', $groupingId = 'all', $debug = false) { $this->view->disable(); // Get our context (this takes care of starting the session, too) $context = $this->getDI()->getShared('ltiContext'); if (!$context->valid) { echo '[{"error":"Invalid lti context"}]'; return; } if (!isset($groupingId)) { echo '[{"error":"No scope grouping ID specified"}]'; return; } // Get the list of videos associated with concepts for the given scope and grouping ID $videos = []; switch ($scope) { case "concept": // Filter based on concept $videos = MappingHelper::videosForConcept($groupingId); break; case "unit": // Filter based on unit $videos = MappingHelper::videosForConcepts(MappingHelper::conceptsInUnit($groupingId)); break; default: // All videos $videos = MappingHelper::videosForConcepts(MappingHelper::allConcepts()); break; } // Find percentage watched for each video foreach ($videos as $key => $video) { $percentageWatched = MasteryHelper::calculateUniqueVideoPercentageForVideo($context->getUserName(), $video, $debug); // Add the percentage to the video $video["percentageWatched"] = $percentageWatched; // Add the modified video back to the original array $videos[$key] = $video; } // Format each video for the frontend $formatted = []; foreach ($videos as $video) { $formatted[] = $video; } if ($debug) { echo "<pre>Getting information for these video IDs in scope {$scope} and ID {$groupingId}\n"; foreach ($videos as $video) { echo $video["Video ID"] . "\n"; } } echo json_encode($formatted); }
public function mappingsAction() { echo "<pre>"; echo "All units\n"; print_r(MappingHelper::allUnits()); echo "<hr>Concepts in unit 4\n"; print_r(MappingHelper::conceptsInUnit("4")); echo "<hr>Questions in concept (lecture number) 1\n"; print_r(MappingHelper::questionsInConcept("1")); echo "<hr>Question info for question 78.4\n"; print_r(MappingHelper::questionInformation("78.4")); echo "<hr>Videos for concept 9\n"; print_r(MappingHelper::videosForConcept("9")); echo "<hr>Resources for concept 1\n"; print_r(MappingHelper::resourcesForConcept("1")); echo "<hr>Concepts within the past 2 weeks: \n"; print_r(MappingHelper::conceptsWithin2Weeks()); }
public static function videosInConceptLength($concept) { $videos = MappingHelper::videosForConcept($concept); $length = 0; foreach ($videos as $vid) { $length += $vid["Video Length"]; } return $length; }
public function resourcesAction() { $this->tag->setTitle('Course Resources | Student Dashboard'); $this->view->pageTitle = 'Course Resources | Student Dashboard'; // Get our context (this takes care of starting the session, too) $context = $this->getDI()->getShared('ltiContext'); // Get list of concepts $conceptsMapping = MappingHelper::allConcepts(); $concepts = []; $resources = []; // Get list of resources for each concept foreach ($conceptsMapping as $c) { // Formatting for view $concepts[] = ["id" => $c["Lecture Number"], "title" => $c["Concept Title"], "date" => $c["Date"]]; // Get resources for each of the concepts $conceptId = $c["Lecture Number"]; $resourceLists[$conceptId] = MappingHelper::resourcesForConcept($conceptId); // Get videos for each of the concepts $videos = MappingHelper::videosForConcept($conceptId); // Format videos to be the same format as ayamel links from the resources.csv mapping foreach ($videos as $video) { $resourceLists[$conceptId][] = ["Lecture Number" => $video["Lecture Number"], "Resource Type" => "ayamel", "Resource Title" => $video["Video Title"], "Resource Link" => $video["Video ID"], "Resource Tracking Number" => $video["Video ID"]]; } } // Figure out which concept to position the list at (based on the current day) $currentConceptID = $conceptsMapping[0]["Date"]; // This is assuming that every concept has a date, and that they are listed in concepts.csv in chronological non-descending order // Find the first concept that's past today, and then use the previous concept $today = strtotime("today"); foreach ($conceptsMapping as $concept) { if (strtotime($concept["Date"]) > $today) { break; } else { $currentConceptID = $concept["Lecture Number"]; // If this concept has a date of today, then stop if (strtotime($concept["Date"]) == $today) { break; } } } $this->view->concepts = $concepts; $this->view->resources = $resourceLists; $this->view->currentConceptID = $currentConceptID; }
public static function calculateUniqueVideoPercentageForConcept($studentId, $conceptId, $debug = false) { // Length of each statement in video seconds $watchedStatementLength = 10; // Find the videos related to this concept $relatedVideos = MappingHelper::videosForConcept($conceptId); $possibleWatchedStatementCount = 0; $userWatchedStatementCount = 0; $videoIds = array(); foreach ($relatedVideos as $video) { // Length of video divided by 10 rounded down will be the total number of possible unique watched statements for that video $possibleWatchedStatementCount += floor($video["Video Length"] / $watchedStatementLength); // Add its ID to a list that we'll fetch watched statements for $videoIds[] = 'https://ayamel.byu.edu/content/' . $video["Video ID"]; } // Calculate how much time these videos were watched // This is more efficient by using an $in query for all videos, rather than querying for each individual video as previously done $statementHelper = new StatementHelper(); $statements = $statementHelper->getStatements("ayamel", ['statement.actor.name' => $studentId, 'statement.verb.id' => 'https://ayamel.byu.edu/watched', 'statement.object.id' => array('$in' => $videoIds)], ['statement.object.id' => true, 'statement.object.definition.extensions' => true]); if ($statements["error"]) { $userWatchedStatementCount = 0; if ($debug) { echo "Error in fetching watched statements for concept {$conceptId} and videos: \n"; print_r($videoIds); } } else { // We need to track unique statements, so student can't get 100% video watched by watching the first half twice $videoTrackers = []; $watchStatementCount = $statements["cursor"]->count(); foreach ($statements["cursor"] as $statement) { // We need to get rid of encoded "."s in extension names $statement = StatementHelper::replaceHtmlEntity($statement["statement"], true); // Set a flag for each rounded timestamp for each video $videoId = $statement["object"]["id"]; $roundedTime = round($statement["object"]["definition"]["extensions"]["https://ayamel.byu.edu/playerTime"] / $watchedStatementLength); if (!isset($videoTrackers[$videoId])) { $videoTrackers[$videoId] = []; } // See if a statement with the same rounded timestamp was already tracked if (isset($videoTrackers[$videoId][$roundedTime]) && $videoTrackers[$videoId][$roundedTime] == true) { $isUnique = false; } else { $isUnique = true; $userWatchedStatementCount++; // Track this statement $videoTrackers[$videoId][$roundedTime] = true; } if ($debug) { print_r($statement); echo "Video id: {$videoId}, rounded time: {$roundedTime}, unique: {$isUnique} \n<hr>"; } } } if ($debug) { echo "Videos for concept {$conceptId} : {$userWatchedStatementCount} unique watched statements out of {$possibleWatchedStatementCount} possible for the following videos: \n"; print_r($videoIds); } // Return percentage (0-100) of videos watched, avoiding division by 0 $percentage = $possibleWatchedStatementCount != 0 ? $userWatchedStatementCount / $possibleWatchedStatementCount : 0; $percentage = round($percentage * 100); return min($percentage, 100); }