asameshimae / Better Bb UBN course list

// ==UserScript==
// @name         Better Bb UBN course list
// @version      2024-02-06
// @description  Show all courses in year/semester groupings and ordered by title, for Bb UBN
// @author       asameshimae
// @match        https://online.manchester.ac.uk/ultra/course
// @icon         https://www.google.com/s2/favicons?sz=64&domain=manchester.ac.uk
// @updateURL    https://openuserjs.org/meta/asameshimae/Better_Bb_UBN_course_list.meta.js
// @downloadURL  https://openuserjs.org/install/asameshimae/Better_Bb_UBN_course_list.user.js
// @grant        none
// @license      MIT
// ==/UserScript==

/* jshint esversion: 8 */

async function init() {
	document.querySelector('#course-columns-current').textContent=''
	let sems = ['1SE','2SE','1YR']
	let semHuman = sem=>['1st Semester','2nd Semester','Full Year'][sems.indexOf(sem)]
	let target = document.querySelector('#course-columns-current')
	let r = await fetch('https://online.manchester.ac.uk/learn/api/v1/users/me/memberships?limit=1000&expand=course.effectiveAvailability')
	let j = await r.json()
	let coursesYears = j.results.filter(e=>e.course.courseId.match(/\-1\d\d1\-(1SE|2SE|1YR)\-/))
	let coursesFixed = j.results.filter(e=>!e.course.courseId.match(/\-1\d\d1\-(1SE|2SE|1YR)\-/))
	let years = [...new Set(coursesYears.map(e=>e.course.courseId.split('-')[3]))].sort().reverse()
	let table = document.createElement('table')
	target.append(table)
	let tr = document.createElement('tr')
	tr.style.verticalAlign='top'
	table.append(tr)
	let td1 = document.createElement('td')
	tr.append(td1)
	years.forEach(yearCode=>{
		let acYearStart2=(yearCode.substr(1,2))
		let yearHuman=`20${acYearStart2}-${(+acYearStart2+1).toString().padStart(2,'0')}`
		let h2 = document.createElement('h2')
		h2.append(document.createTextNode(yearHuman))
		td1.append(h2)
		let thisYearCourses = coursesYears.filter(e=>e.course.courseId.split('-')[3]===yearCode)
		for(let sem of sems) {
			let thisSemCourses = thisYearCourses.filter(e=>e.course.courseId.split('-')[4]===sem)
			if(thisSemCourses.length) {
				let thisSemCourseNames = thisSemCourses.map(e=>e.course.displayName).sort()
				let h3 = document.createElement('h3')
				h3.append(document.createTextNode(semHuman(sem)))
				td1.append(h3)
				let ul = document.createElement('ul')
				thisSemCourseNames.forEach(name=>{
					let thisCourseUrl = thisSemCourses.find(e=>e.course.displayName===name).course.externalAccessUrl
					let li = document.createElement('li')
					let a = document.createElement('a')
					a.append(document.createTextNode(name))
					a.href = thisCourseUrl
					li.append(a)
					ul.append(li)
				})
				td1.append(ul)
			}
		}
	})
	let td2 = document.createElement('td')
	td2.style.paddingLeft='1em'
	tr.append(td2)
	let h2 = document.createElement('h2')
	h2.append(document.createTextNode('Organisations'))
	td2.append(h2)
	let ul = document.createElement('ul')
	let orgCourseNames = coursesFixed.map(e=>e.course.displayName).sort()
	orgCourseNames.forEach(name=>{
		let thisCourseUrl = coursesFixed.find(e=>e.course.displayName===name).course.externalAccessUrl
		let li = document.createElement('li')
		let a = document.createElement('a')
		a.append(document.createTextNode(name))
		a.href = thisCourseUrl
		li.append(a)
		ul.append(li)
	})
	td2.append(ul)
}

var i

(function(){
    i = setInterval(()=>{
        let test = document.querySelector('#course-columns-current')
        if(test) {
            clearInterval(i)
            init()
        }
    },500)
})()