Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
KevsterAmp committed Sep 7, 2023
2 parents b6cffe9 + a87df7e commit 5abac9b
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 28 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# PUPSIS-Schedule-Exporter
A web extension that converts the schedule of students from PUPSIS to ICalendar (.ics) or csv file so that they can easily import their schedules on other popular calendar tools like Google Calendar.
A web extension that converts the schedule of students from PUPSIS to ICalendar (.ics), csv or json so that they can easily import their schedules on other popular calendar tools like Google Calendar.

**WARNING, WEB-EXTENSION IN GOOGLE CHROME IS OUTDATED** <br>
**GO TO [INSTALLATION GUIDE](img/README.md) TO DOWNLOAD UPDATED WEB EXTENSION** <br>
Expand All @@ -18,6 +18,7 @@ For **developers** that wants to contribute to this project, check the **test/ht
# Features
- convert to ICalendar (.ics) format, used for easy export on popular calendar tools like Google Calendar
- convert to CSV, in a calendar style format, for users that do not use any calendar tools.
- convert to JSON, which can be imported on [schedulemaker.io](https://schedulemaker.io/)

*Tip: it's a good idea to set the end date to the last day of their semester. This way, the recurring events will automatically stop when the semester ends.*

Expand All @@ -29,4 +30,4 @@ For **developers** that wants to contribute to this project, check the **test/ht
- [x] Return error at empty schedule
- [x] Implement CSV feature (Implemented by @szy-kenn!)
- [x] Add UI/Styling (Thanks @egg-lou, @yam-1111, @szy-kenn!)
- [ ] Implement export to schedulemaker.io via json feature (ongoing by @kevsteramp)
- [x] Implement export to schedulemaker.io via json feature
2 changes: 0 additions & 2 deletions web-extension/contentScript.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@ function parseTableData(tableContent) {
let temp = data[6].textContent.trim();
temp = temp.split("Faculty:")
schedule = temp[0];
console.log(temp);
let instructor = temp[1];
if (isNumber(schedule[0])) {
let x = schedule.split(" ");
console.log(x);
x = x.slice(5);
x = x.join(" ");
schedule = x;
Expand Down
1 change: 1 addition & 0 deletions web-extension/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ <h2 class="pop-title">PUPSIS-Schedule-Exporter</h2>
<select name="file-type" id="fileType">
<option value="ics" selected>.ics</option>
<option value="csv">.csv</option>
<option value="json">.json</option>
</select>
</div>

Expand Down
154 changes: 130 additions & 24 deletions web-extension/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
textContent = "ICalendar";
}
else if (preferredFileType === 'json') {
//insert json function here
data = assignColorsToSubjects(output);
data = jsonToScheduleMaker(data);
textContent = "JSON";
}
downloadFile(data, "schedule", preferredFileType);
Expand Down Expand Up @@ -129,13 +130,10 @@ function separateSchedules(data) {
const output = {
subject_code: data[i].subject_code,
subject: data[i].subject,
"Start Date": getDayDate(days[0]),
"Scheduled Day": days[0],
"All Day Event": "FALSE",
"Start Time": formatTime(times[0].split("-")[0]),
"End Time": formatTime(times[0].split("-")[1]),
Location: "",
Description: ""
start_date: getDayDate(days[0]),
scheduled_day: days[0],
start_time: formatTime(times[0].split("-")[0]),
end_time: formatTime(times[0].split("-")[1])
}
csvObject.push(output);
}
Expand All @@ -144,13 +142,10 @@ function separateSchedules(data) {
const output = {
subject_code: data[i].subject_code,
subject: data[i].subject,
"Start Date": getDayDate(days[j]),
"Scheduled Day": days[j],
"All Day Event": "FALSE",
"Start Time": formatTime(times[j].split("-")[0]),
"End Time": formatTime(times[j].split("-")[1]),
Location: "",
Description: ""
start_date: getDayDate(days[j]),
scheduled_day: days[j],
start_time: formatTime(times[j].split("-")[0]),
end_time: formatTime(times[j].split("-")[1])
}
csvObject.push(output);
}
Expand Down Expand Up @@ -181,9 +176,9 @@ PRODID:-//PUPSIS TO ICS//Event Calendar//EN\n`;
}

for (const event of events) {
const uid = event.subject.replace(/\s+/g, '') + event['Start Date'] + event['Start Time'];
const startDate = parseDateTime(event['Start Date'], event['Start Time']);
const endDate = parseDateTime(event['Start Date'], event['End Time']);
const uid = event.subject.replace(/\s+/g, '') + event['start_date'] + event['start_time'];
const startDate = parseDateTime(event['start_date'], event['start_time']);
const endDate = parseDateTime(event['start_date'], event['end_time']);

if (!startDate || !endDate) {
console.error('Invalid date or time format.');
Expand Down Expand Up @@ -241,8 +236,13 @@ function downloadFile(content, filename, fileType) {

if (fileType === 'csv') {
contentType = 'text/csv';
} else if (fileType === 'ics') {
}
else if (fileType === 'ics') {
contentType = 'text/calendar;charset=utf-8';
}
else if (fileType === "json") {
content = JSON.stringify(content, null, 2);
contentType = "application/json"
}

const blob = new Blob([content], {type: contentType});
Expand Down Expand Up @@ -334,18 +334,124 @@ function jsonToCSV(output) {
output.forEach(row => {

// get all the needed values from the current row
let subjectTimeslotIdx = timeslots.indexOf(row["Start Time"]);
let dayIdx = daysOfWeek.indexOf(row["Scheduled Day"]);
let subjectTimeslotIdx = timeslots.indexOf(row["start_time"]);
let dayIdx = daysOfWeek.indexOf(row["scheduled_day"]);
let subject = row["subject_code"].toString().replace(",", "");

// set the start time to the end time's timeslot value to the current subject
// set the start_time to the end_time's timeslot value to the current subject
// ex. (8:00 AM - 9:30 AM - <subject>)
while (timeslots[subjectTimeslotIdx] !== row["End Time"]) {
while (timeslots[subjectTimeslotIdx] !== row["end_time"]) {
csv[subjectTimeslotIdx + 1][dayIdx + 1] = subject;
subjectTimeslotIdx++;
}

});

return csv.join('\n');
};
};


/**
*
* @param {object} - object containing the rows of the extracted and separated schedule
* @returns an object compatible for conversion to Schedulemaker.io via json file
*/
function jsonToScheduleMaker(output) {
//temp output of json
let events = [];
const jsonDaysWeek = ['M', 'T', 'W', 'TH', 'F', 'S', 'SUN']
for (let i = 0; i < output.length; i++) {
const eventEntry = {
title: output[i].subject,
description: "",
day: jsonDaysWeek.indexOf(output[i].scheduled_day),
start: convert12hrTo24hr(output[i].start_time),
end: convert12hrTo24hr(output[i].end_time),
color: output[i].color,
icon: null
}
events.push(eventEntry);
}
const jsonScheduleMaker = {
"title": "My Schedule",
"events": events,
"settings": {
"timeFormat": 12,
"timeStep": 60,
"weekLength": 7,
"weekStart": 0,
"minHourRange": 8,
"adaptive": true,
"dense": false
}
}
return jsonScheduleMaker
}


/**
*
* @param {time} - time in 12hr format
* @returns - time in 24hr format
*/
function convert12hrTo24hr(time12hr) {
// Split the input time into hours, minutes, and AM/PM parts
const parts = time12hr.match(/(\d+):(\d+) (AM|PM)/);

if (!parts || parts.length !== 4) {
// Invalid input format
return "Invalid time format";
}

let hours = parseInt(parts[1]);
const minutes = parseInt(parts[2]);
const period = parts[3];

if (hours === 12) {
// 12 AM should be converted to 00:00
if (period === "AM") {
hours = 0;
}
} else if (period === "PM") {
// Convert PM hours to 24-hour format
hours += 12;
}

// Format the result as HH:mm
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
}


/**
*
* @param {object} - the array of schedules created by separateSchedules function
* @returns - object with added color format
*/
function assignColorsToSubjects(output) {
const subjects = output.map(item => item.subject);
const uniqueSubjects = [...new Set(subjects)];
const colors = [
'#FF5733', // Dark Coral
'#3377FF', // Medium Blue
'#FF338A', // Dark Pink
'#3333FF', // Dark Slate Blue
'#FF33A4', // Dark Magenta
'#33B0FF', // Deep Sky Blue
'#FF9D33', // Dark Orange
'#3367FF', // Royal Blue
'#FF336A', // Red-Orange
'#33FFD4', // Medium Aquamarine
'#FF3333', // Dark Red
];

const colorMap = {};

uniqueSubjects.forEach((subject, index) => {
colorMap[subject] = colors[index];
});

return output.map(item => ({
...item,
color: colorMap[item.subject],
}));
}

0 comments on commit 5abac9b

Please sign in to comment.