Skip to content

Instantly share code, notes, and snippets.

@getjump
Created September 22, 2019 04:24
Show Gist options
  • Save getjump/a9864aef2f6ae9b309e5997e2c9c878f to your computer and use it in GitHub Desktop.
Save getjump/a9864aef2f6ae9b309e5997e2c9c878f to your computer and use it in GitHub Desktop.
Экспортирует расписание с личного кабинета ДВФУ в iCal для дальнейшего импорта например в Google Calendar
// ЗАПУСКАТЬ ОТСЮДА: https://univer.dvfu.ru/schedule
// Проверено на работоспособность в Firefox
// Копировать в консоль, сохранить файл, импортировать например в Google Calendar
(async function() {
var semesterStart = '2019-09-23';
var semesterEnd = '2020-01-03';
// Function to download data to a file
function download(data, filename, type) {
var file = new Blob([data], {type: type});
if (window.navigator.msSaveOrOpenBlob) // IE10+
window.navigator.msSaveOrOpenBlob(file, filename);
else { // Others
var a = document.createElement("a"),
url = URL.createObjectURL(file);
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
}
function getWeekNumber(d) {
// Copy date so don't modify original
d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));
// Set to nearest Thursday: current date + 4 - current day number
// Make Sunday's day number 7
d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay()||7));
// Get first day of year
var yearStart = new Date(Date.UTC(d.getUTCFullYear(),0,1));
// Calculate full weeks to nearest Thursday
var weekNo = Math.ceil(( ( (d - yearStart) / 86400000) + 1)/7);
// Return array of year and week number
return [d.getUTCFullYear(), weekNo];
}
function dynamicallyLoadScript(content) {
var script = document.createElement("script"); // create a script DOM node
script.type = 'text/javascript';
script.textContent = content;
document.head.appendChild(script); // add it to the end of the head section of the page (could change 'head' to 'body' to add it to the end of the body section instead)
}
dynamicallyLoadScript(atob('dmFyIHNhdmVBcz1zYXZlQXN8fGZ1bmN0aW9uKGUpeyJ1c2Ugc3RyaWN0IjtpZih0eXBlb2YgZT09PSJ1bmRlZmluZWQifHx0eXBlb2YgbmF2aWdhdG9yIT09InVuZGVmaW5lZCImJi9NU0lFIFsxLTldXC4vLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkpe3JldHVybn12YXIgdD1lLmRvY3VtZW50LG49ZnVuY3Rpb24oKXtyZXR1cm4gZS5VUkx8fGUud2Via2l0VVJMfHxlfSxyPXQuY3JlYXRlRWxlbWVudE5TKCJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hodG1sIiwiYSIpLG89ImRvd25sb2FkImluIHIsYT1mdW5jdGlvbihlKXt2YXIgdD1uZXcgTW91c2VFdmVudCgiY2xpY2siKTtlLmRpc3BhdGNoRXZlbnQodCl9LGk9L2NvbnN0cnVjdG9yL2kudGVzdChlLkhUTUxFbGVtZW50KXx8ZS5zYWZhcmksZj0vQ3JpT1NcL1tcZF0rLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHU9ZnVuY3Rpb24odCl7KGUuc2V0SW1tZWRpYXRlfHxlLnNldFRpbWVvdXQpKGZ1bmN0aW9uKCl7dGhyb3cgdH0sMCl9LHM9ImFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSIsZD0xZTMqNDAsYz1mdW5jdGlvbihlKXt2YXIgdD1mdW5jdGlvbigpe2lmKHR5cGVvZiBlPT09InN0cmluZyIpe24oKS5yZXZva2VPYmplY3RVUkwoZSl9ZWxzZXtlLnJlbW92ZSgpfX07c2V0VGltZW91dCh0LGQpfSxsPWZ1bmN0aW9uKGUsdCxuKXt0PVtdLmNvbmNhdCh0KTt2YXIgcj10Lmxlbmd0aDt3aGlsZShyLS0pe3ZhciBvPWVbIm9uIit0W3JdXTtpZih0eXBlb2Ygbz09PSJmdW5jdGlvbiIpe3RyeXtvLmNhbGwoZSxufHxlKX1jYXRjaChhKXt1KGEpfX19fSxwPWZ1bmN0aW9uKGUpe2lmKC9eXHMqKD86dGV4dFwvXFMqfGFwcGxpY2F0aW9uXC94bWx8XFMqXC9cUypcK3htbClccyo7LipjaGFyc2V0XHMqPVxzKnV0Zi04L2kudGVzdChlLnR5cGUpKXtyZXR1cm4gbmV3IEJsb2IoW1N0cmluZy5mcm9tQ2hhckNvZGUoNjUyNzkpLGVdLHt0eXBlOmUudHlwZX0pfXJldHVybiBlfSx2PWZ1bmN0aW9uKHQsdSxkKXtpZighZCl7dD1wKHQpfXZhciB2PXRoaXMsdz10LnR5cGUsbT13PT09cyx5LGg9ZnVuY3Rpb24oKXtsKHYsIndyaXRlc3RhcnQgcHJvZ3Jlc3Mgd3JpdGUgd3JpdGVlbmQiLnNwbGl0KCIgIikpfSxTPWZ1bmN0aW9uKCl7aWYoKGZ8fG0mJmkpJiZlLkZpbGVSZWFkZXIpe3ZhciByPW5ldyBGaWxlUmVhZGVyO3Iub25sb2FkZW5kPWZ1bmN0aW9uKCl7dmFyIHQ9Zj9yLnJlc3VsdDpyLnJlc3VsdC5yZXBsYWNlKC9eZGF0YTpbXjtdKjsvLCJkYXRhOmF0dGFjaG1lbnQvZmlsZTsiKTt2YXIgbj1lLm9wZW4odCwiX2JsYW5rIik7aWYoIW4pZS5sb2NhdGlvbi5ocmVmPXQ7dD11bmRlZmluZWQ7di5yZWFkeVN0YXRlPXYuRE9ORTtoKCl9O3IucmVhZEFzRGF0YVVSTCh0KTt2LnJlYWR5U3RhdGU9di5JTklUO3JldHVybn1pZigheSl7eT1uKCkuY3JlYXRlT2JqZWN0VVJMKHQpfWlmKG0pe2UubG9jYXRpb24uaHJlZj15fWVsc2V7dmFyIG89ZS5vcGVuKHksIl9ibGFuayIpO2lmKCFvKXtlLmxvY2F0aW9uLmhyZWY9eX19di5yZWFkeVN0YXRlPXYuRE9ORTtoKCk7Yyh5KX07di5yZWFkeVN0YXRlPXYuSU5JVDtpZihvKXt5PW4oKS5jcmVhdGVPYmplY3RVUkwodCk7c2V0VGltZW91dChmdW5jdGlvbigpe3IuaHJlZj15O3IuZG93bmxvYWQ9dTthKHIpO2goKTtjKHkpO3YucmVhZHlTdGF0ZT12LkRPTkV9KTtyZXR1cm59UygpfSx3PXYucHJvdG90eXBlLG09ZnVuY3Rpb24oZSx0LG4pe3JldHVybiBuZXcgdihlLHR8fGUubmFtZXx8ImRvd25sb2FkIixuKX07aWYodHlwZW9mIG5hdmlnYXRvciE9PSJ1bmRlZmluZWQiJiZuYXZpZ2F0b3IubXNTYXZlT3JPcGVuQmxvYil7cmV0dXJuIGZ1bmN0aW9uKGUsdCxuKXt0PXR8fGUubmFtZXx8ImRvd25sb2FkIjtpZighbil7ZT1wKGUpfXJldHVybiBuYXZpZ2F0b3IubXNTYXZlT3JPcGVuQmxvYihlLHQpfX13LmFib3J0PWZ1bmN0aW9uKCl7fTt3LnJlYWR5U3RhdGU9dy5JTklUPTA7dy5XUklUSU5HPTE7dy5ET05FPTI7dy5lcnJvcj13Lm9ud3JpdGVzdGFydD13Lm9ucHJvZ3Jlc3M9dy5vbndyaXRlPXcub25hYm9ydD13Lm9uZXJyb3I9dy5vbndyaXRlZW5kPW51bGw7cmV0dXJuIG19KHR5cGVvZiBzZWxmIT09InVuZGVmaW5lZCImJnNlbGZ8fHR5cGVvZiB3aW5kb3chPT0idW5kZWZpbmVkIiYmd2luZG93fHx0aGlzLmNvbnRlbnQpO2lmKHR5cGVvZiBtb2R1bGUhPT0idW5kZWZpbmVkIiYmbW9kdWxlLmV4cG9ydHMpe21vZHVsZS5leHBvcnRzLnNhdmVBcz1zYXZlQXN9ZWxzZSBpZih0eXBlb2YgZGVmaW5lIT09InVuZGVmaW5lZCImJmRlZmluZSE9PW51bGwmJmRlZmluZS5hbWQhPT1udWxsKXtkZWZpbmUoIkZpbGVTYXZlci5qcyIsZnVuY3Rpb24oKXtyZXR1cm4gc2F2ZUFzfSl9LyohIGljcy5qcyBXZWQgU2VwdCAxNCAyMDE3ICovCnZhciBpY3M9ZnVuY3Rpb24oZSx0KXsidXNlIHN0cmljdCI7e2lmKCEobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKCJNU0lFIik+LTEmJi0xPT1uYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoIk1TSUUgMTAiKSkpe3ZvaWQgMD09PWUmJihlPSJkZWZhdWx0Iiksdm9pZCAwPT09dCYmKHQ9IkNhbGVuZGFyIik7dmFyIHI9LTEhPT1uYXZpZ2F0b3IuYXBwVmVyc2lvbi5pbmRleE9mKCJXaW4iKT8iXHJcbiI6IlxuIixuPVtdLGk9WyJCRUdJTjpWQ0FMRU5EQVIiLCJQUk9ESUQ6Iit0LCJWRVJTSU9OOjIuMCJdLmpvaW4ociksbz1yKyJFTkQ6VkNBTEVOREFSIixhPVsiU1UiLCJNTyIsIlRVIiwiV0UiLCJUSCIsIkZSIiwiU0EiXTtyZXR1cm57ZXZlbnRzOmZ1bmN0aW9uKCl7cmV0dXJuIG59LGNhbGVuZGFyOmZ1bmN0aW9uKCl7cmV0dXJuIGkrcituLmpvaW4ocikrb30sYWRkRXZlbnQ6ZnVuY3Rpb24odCxpLG8sbCx1LHMpe2lmKHZvaWQgMD09PXR8fHZvaWQgMD09PWl8fHZvaWQgMD09PW98fHZvaWQgMD09PWx8fHZvaWQgMD09PXUpcmV0dXJuITE7aWYocyYmIXMucnJ1bGUpe2lmKCJZRUFSTFkiIT09cy5mcmVxJiYiTU9OVEhMWSIhPT1zLmZyZXEmJiJXRUVLTFkiIT09cy5mcmVxJiYiREFJTFkiIT09cy5mcmVxKXRocm93IlJlY3VycmVuY2UgcnJ1bGUgZnJlcXVlbmN5IG11c3QgYmUgcHJvdmlkZWQgYW5kIGJlIG9uZSBvZiB0aGUgZm9sbG93aW5nOiAnWUVBUkxZJywgJ01PTlRITFknLCAnV0VFS0xZJywgb3IgJ0RBSUxZJyI7aWYocy51bnRpbCYmaXNOYU4oRGF0ZS5wYXJzZShzLnVudGlsKSkpdGhyb3ciUmVjdXJyZW5jZSBycnVsZSAndW50aWwnIG11c3QgYmUgYSB2YWxpZCBkYXRlIHN0cmluZyI7aWYocy5pbnRlcnZhbCYmaXNOYU4ocGFyc2VJbnQocy5pbnRlcnZhbCkpKXRocm93IlJlY3VycmVuY2UgcnJ1bGUgJ2ludGVydmFsJyBtdXN0IGJlIGFuIGludGVnZXIiO2lmKHMuY291bnQmJmlzTmFOKHBhcnNlSW50KHMuY291bnQpKSl0aHJvdyJSZWN1cnJlbmNlIHJydWxlICdjb3VudCcgbXVzdCBiZSBhbiBpbnRlZ2VyIjtpZih2b2lkIDAhPT1zLmJ5ZGF5KXtpZigiW29iamVjdCBBcnJheV0iIT09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHMuYnlkYXkpKXRocm93IlJlY3VycmVuY2UgcnJ1bGUgJ2J5ZGF5JyBtdXN0IGJlIGFuIGFycmF5IjtpZihzLmJ5ZGF5Lmxlbmd0aD43KXRocm93IlJlY3VycmVuY2UgcnJ1bGUgJ2J5ZGF5JyBhcnJheSBtdXN0IG5vdCBiZSBsb25nZXIgdGhhbiB0aGUgNyBkYXlzIGluIGEgd2VlayI7cy5ieWRheT1zLmJ5ZGF5LmZpbHRlcihmdW5jdGlvbihlLHQpe3JldHVybiBzLmJ5ZGF5LmluZGV4T2YoZSk9PXR9KTtmb3IodmFyIGMgaW4gcy5ieWRheSlpZihhLmluZGV4T2Yocy5ieWRheVtjXSk8MCl0aHJvdyJSZWN1cnJlbmNlIHJydWxlICdieWRheScgdmFsdWVzIG11c3QgaW5jbHVkZSBvbmx5IHRoZSBmb2xsb3dpbmc6ICdTVScsICdNTycsICdUVScsICdXRScsICdUSCcsICdGUicsICdTQScifX12YXIgZz1uZXcgRGF0ZShsKSxkPW5ldyBEYXRlKHUpLGY9bmV3IERhdGUsUz0oIjAwMDAiK2cuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpKS5zbGljZSgtNCksRT0oIjAwIisoZy5nZXRNb250aCgpKzEpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSx2PSgiMDAiK2cuZ2V0RGF0ZSgpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSx5PSgiMDAiK2cuZ2V0SG91cnMoKS50b1N0cmluZygpKS5zbGljZSgtMiksQT0oIjAwIitnLmdldE1pbnV0ZXMoKS50b1N0cmluZygpKS5zbGljZSgtMiksVD0oIjAwIitnLmdldFNlY29uZHMoKS50b1N0cmluZygpKS5zbGljZSgtMiksYj0oIjAwMDAiK2QuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpKS5zbGljZSgtNCksRD0oIjAwIisoZC5nZXRNb250aCgpKzEpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSxOPSgiMDAiK2QuZ2V0RGF0ZSgpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSxoPSgiMDAiK2QuZ2V0SG91cnMoKS50b1N0cmluZygpKS5zbGljZSgtMiksST0oIjAwIitkLmdldE1pbnV0ZXMoKS50b1N0cmluZygpKS5zbGljZSgtMiksUj0oIjAwIitkLmdldE1pbnV0ZXMoKS50b1N0cmluZygpKS5zbGljZSgtMiksTT0oIjAwMDAiK2YuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpKS5zbGljZSgtNCksdz0oIjAwIisoZi5nZXRNb250aCgpKzEpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSxMPSgiMDAiK2YuZ2V0RGF0ZSgpLnRvU3RyaW5nKCkpLnNsaWNlKC0yKSxPPSgiMDAiK2YuZ2V0SG91cnMoKS50b1N0cmluZygpKS5zbGljZSgtMikscD0oIjAwIitmLmdldE1pbnV0ZXMoKS50b1N0cmluZygpKS5zbGljZSgtMiksWT0oIjAwIitmLmdldE1pbnV0ZXMoKS50b1N0cmluZygpKS5zbGljZSgtMiksVT0iIixWPSIiO3krQStUK2grSStSIT0wJiYoVT0iVCIreStBK1QsVj0iVCIraCtJK1IpO3ZhciBCLEM9UytFK3YrVSxqPWIrRCtOK1YsbT1NK3crTCsoIlQiK08rcCtZKTtpZihzKWlmKHMucnJ1bGUpQj1zLnJydWxlO2Vsc2V7aWYoQj0icnJ1bGU6RlJFUT0iK3MuZnJlcSxzLnVudGlsKXt2YXIgeD1uZXcgRGF0ZShEYXRlLnBhcnNlKHMudW50aWwpKS50b0lTT1N0cmluZygpO0IrPSI7VU5USUw9Iit4LnN1YnN0cmluZygwLHgubGVuZ3RoLTEzKS5yZXBsYWNlKC9bLV0vZywiIikrIjAwMDAwMFoifXMuaW50ZXJ2YWwmJihCKz0iO0lOVEVSVkFMPSIrcy5pbnRlcnZhbCkscy5jb3VudCYmKEIrPSI7Q09VTlQ9IitzLmNvdW50KSxzLmJ5ZGF5JiZzLmJ5ZGF5Lmxlbmd0aD4wJiYoQis9IjtCWURBWT0iK3MuYnlkYXkuam9pbigiLCIpKX0obmV3IERhdGUpLnRvSVNPU3RyaW5nKCk7dmFyIEg9WyJCRUdJTjpWRVZFTlQiLCJVSUQ6IituLmxlbmd0aCsiQCIrZSwiQ0xBU1M6UFVCTElDIiwiREVTQ1JJUFRJT046IitpLCJEVFNUQU1QO1ZBTFVFPURBVEUtVElNRToiK20sIkRUU1RBUlQ7VkFMVUU9REFURS1USU1FOiIrQywiRFRFTkQ7VkFMVUU9REFURS1USU1FOiIraiwiTE9DQVRJT046IitvLCJTVU1NQVJZO0xBTkdVQUdFPWVuLXVzOiIrdCwiVFJBTlNQOlRSQU5TUEFSRU5UIiwiRU5EOlZFVkVOVCJdO3JldHVybiBCJiZILnNwbGljZSg0LDAsQiksSD1ILmpvaW4ociksbi5wdXNoKEgpLEh9LGRvd25sb2FkOmZ1bmN0aW9uKGUsdCl7aWYobi5sZW5ndGg8MSlyZXR1cm4hMTt0PXZvaWQgMCE9PXQ/dDoiLmljcyIsZT12b2lkIDAhPT1lP2U6ImNhbGVuZGFyIjt2YXIgYSxsPWkrcituLmpvaW4ocikrbztpZigtMT09PW5hdmlnYXRvci51c2VyQWdlbnQuaW5kZXhPZigiTVNJRSAxMCIpKWE9bmV3IEJsb2IoW2xdKTtlbHNle3ZhciB1PW5ldyBCbG9iQnVpbGRlcjt1LmFwcGVuZChsKSxhPXUuZ2V0QmxvYigidGV4dC94LXZDYWxlbmRhcjtjaGFyc2V0PSIrZG9jdW1lbnQuY2hhcmFjdGVyU2V0KX1yZXR1cm4gc2F2ZUFzKGEsZSt0KSxsfSxidWlsZDpmdW5jdGlvbigpe3JldHVybiEobi5sZW5ndGg8MSkmJmkrcituLmpvaW4ocikrb319fWNvbnNvbGUubG9nKCJVbnN1cHBvcnRlZCBCcm93c2VyIil9fTsK'));
var ppsId = $('input[name=pps_id]')[0].value;
var csrf = $('meta[name=csrf-token]').attr('content');
var data = await fetch('https://univer.dvfu.ru/schedule/get/?type=listWeek&start=' + semesterStart + '&end=' + semesterEnd + '&ppsId=' + ppsId, {
"credentials": "include",
"headers": {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:69.0) Gecko/20100101 Firefox/69.0",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Accept-Language": "ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3",
"X-CSRF-Token": csrf,
"X-Requested-With": "XMLHttpRequest"
},
"referrer": "https://univer.dvfu.ru/schedule",
"method": "GET",
"mode": "cors"
});
var dataJson = await data.json();
var cal = ics();
let busyDaysHash = {};
for (let event of dataJson.events) {
let dateStart = new Date(event.start);
let dateEnd = new Date(event.end);
let subgroup = event.subgroup;
let hashedString = dateStart.getDay().toString() + dateStart.getHours().toString() + dateStart.getMinutes().toString() + subgroup.toString();
if (hashedString in busyDaysHash) {
let busyDay = busyDaysHash[hashedString];
let week = getWeekNumber(dateStart)[1];
if (week < busyDay.week) {
// YEAR SWITCH
continue;
}
busyDay.frequency = week - busyDay.week;
busyDay.week = week;
} else {
busyDaysHash[hashedString] = { event: event, week: getWeekNumber(dateStart)[1] };
}
}
console.log(busyDaysHash);
var twoLetterWeekDays = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
Object.values(busyDaysHash).forEach(function(bd) {
console.log(bd);
var subgroup = bd.event.subgroup ? ' Подгруппа ' + bd.event.subgroup + ' ': '';
cal.addEvent(bd.event.title + ' (' + bd.event.pps_load + ') ' + subgroup, bd.event.group + ' ' + bd.event.pps_load, bd.event.classroom, bd.event.start, bd.event.end, {
freq: 'WEEKLY',
until: semesterEnd,
interval: bd.frequency,
byday: [ twoLetterWeekDays[(new Date(bd.event.start)).getDay()] ]
});
});
cal.download('classes-calendar');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment