您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Mess around with schoolbook.ge
// ==UserScript== // @name Schoolbook Tools // @description Mess around with schoolbook.ge // @icon https://eservices.schoolbook.ge/Images/sb-logo-blue.png // @author Naviamold // @license MIT // @version 2.6 // @namespace https://github.com/naviamold1 // @homepage https://greasyfork.org/en/scripts/459858-schoolbook-tools // @match *://*.schoolbook.ge/* // @exclude *://schoolbook.ge/* // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function () { 'use strict'; // do not change anything here if you don't know what you are doing! const settings = { // @ts-ignore changeGrade: GM_getValue('changeGrade'), // @ts-ignore changeAttendance: GM_getValue('changeAttendance'), // @ts-ignore liveGradeUpdate: GM_getValue('liveGradeUpdate'), // @ts-ignore gradeViewer: GM_getValue('gradeViewer'), // @ts-ignore hideComments: GM_getValue('hideComments'), // @ts-ignore attendanceViewer: GM_getValue('attendanceViewer') }; // Add a button to open the settings dialog $('#pageBody') ?.prepend(`<button data-open-modal id="openSettingsButton">Open Settings</button> <dialog data-modal id="schoolbook_tools_settings_dialog"> <h2>Script Settings</h2> <label for="changeGrade">(CLIENT SIDE) Change Grade:</label> <input type="text" id="changeGrade" value="${ settings.changeGrade ?? '' }"> <br> <label for="changeAttendance">(CLIENT SIDE) Change Attendance:</label> <input type="text" id="changeAttendance" value="${ settings.changeAttendance ?? '' }"> <br> <label for="liveGradeUpdate">Live Grade Update:</label> <input type="checkbox" id="liveGradeUpdate" ${ settings.liveGradeUpdate ? 'checked' : '' }> <br> <label for="gradeViewer">Grade Viewer:</label> <input type="checkbox" id="gradeViewer" ${ settings.gradeViewer ? 'checked' : '' }> <br> <label for="attendanceViewer">Attendance Viewer:</label> <input type="checkbox" id="attendanceViewer" ${ settings.attendanceViewer ? 'checked' : '' }> <br> <label for="hideComments">(CLIENT SIDE) Hide Comments:</label> <input type="checkbox" id="hideComments" ${ settings.hideComments ? 'checked' : '' }> <br> <a href='https://github.com/Naviamold1/schoolbook-filterlist'>Block Ads</a> <br> <br> <button data-close-modal id="saveSettingsButton">Save Settings</button> <button data-close-modal id="cancelSettingsButton">Cancel</button> </dialog>`); const sanitizeInput = (query) => { const inp = document.querySelector(query); if (inp && inp.value.trim() !== '') { return inp.value.trim(); } return ''; }; const dialog = document.querySelector('#schoolbook_tools_settings_dialog'); document .querySelector('#openSettingsButton') .addEventListener('click', () => dialog.showModal()); document .querySelector('#cancelSettingsButton') .addEventListener('click', () => dialog.close()); document .querySelector('#saveSettingsButton') .addEventListener('click', () => { // @ts-ignore GM_setValue('changeGrade', sanitizeInput('#changeGrade')); // @ts-ignore GM_setValue('changeAttendance', sanitizeInput('#changeAttendance')); // @ts-ignore GM_setValue( 'liveGradeUpdate', document.querySelector('#liveGradeUpdate').checked ); // @ts-ignore GM_setValue( 'gradeViewer', document.querySelector('#gradeViewer').checked ); // @ts-ignore GM_setValue( 'attendanceViewer', document.querySelector('#attendanceViewer').checked ); // @ts-ignore GM_setValue( 'hideComments', document.querySelector('#hideComments').checked ); document.querySelector('#schoolbook_tools_settings_dialog').close(); window.location.reload(); }); const totalAvgGradePath = '#saertosashualo > span, .otherRow > span'; const totalAvgAttendPath = '.sec span'; // Better Timetable const colors = ['#BE2727', '#F5FF2D', '#15D13D', '']; const textColors = ['#E0E6E1', '#1C0316', '#1C0316', '']; const currentTime = new Date().getTime(); const endTime = currentTime + 10 * 1000; let checkExist = setInterval(() => { if ( document.querySelectorAll( '#daysList > div > div.owl-stage-outer > div > div > div > a > ol' ).length >= 5 ) { clearInterval(checkExist); const subjects = document.querySelectorAll( '#daysList > div > div.owl-stage-outer > div > div > div > a > ol > li' ); subjects.forEach((elem) => { let currentColorIndex = 0; elem.addEventListener('click', () => { const currentColor = colors[currentColorIndex]; const currentTextColor = textColors[currentColorIndex]; elem.style.backgroundColor = currentColor; elem.style.color = currentTextColor; currentColorIndex = (currentColorIndex + 1) % colors.length; let subj_name = elem.innerText; document .querySelectorAll( '#subs > div.owl-carousel.subjects.owl-loaded.owl-drag > div.owl-stage-outer > div > div > div > span' ) .forEach((e) => { if ( subj_name.replace(/ \d\d:\d\d/gm, '').replace(' ', '') == e.innerText.replace(' ', '') ) { let elem = e.parentNode; if (!elem) return; elem.style.backgroundColor = currentColor; elem.style.color = currentTextColor; $(elem.parentNode).insertBefore( document.querySelector( '#subs > div.owl-carousel.subjects.owl-loaded.owl-drag > div.owl-stage-outer > div > div:nth-child(1)' ) ); } }); }); }); } else if (endTime < new Date().getTime()) { clearInterval(checkExist); console.log('not found in specified time.'); return; } else { console.log('waiting for element to be present…'); } }, 100); // Logic Functions function newGrade(grade) { let grades = document.querySelectorAll(`.avg_value, ${totalAvgGradePath}`); grades.forEach((val) => (val.textContent = grade)); } function newAttendance(attendance) { let attendances = document.querySelectorAll(`.prc, ${totalAvgAttendPath}`); attendances.forEach((val) => (val.textContent = attendance)); } function removeComments() { let comments = document.querySelectorAll( '.notificationsList, .notificationsListalter, .homeworkContent' ); comments.forEach((mes) => (mes.style.display = 'none')); } function getAvg(query) { let numbers = []; query.forEach((el) => { let text = el.textContent; if (text) { let number = parseInt(text.replace(/\D/g, ''), 10); if (!isNaN(number)) { numbers.push(number); } } }); const sum = numbers.reduce((acc, val) => acc + val, 0); const avg = numbers.length > 0 ? sum / numbers.length : 0; return Math.round(avg * 100) / 100; } function waitUntilAvgPresent(selector, elem, close = false) { const currentTime = new Date().getTime(); const endTime = currentTime + 5 * 1000; let checkExist = setInterval(() => { if (document.querySelectorAll(selector).length) { clearInterval(checkExist); const avg = getAvg(document.querySelectorAll(selector)); elem.textContent = avg.toString(); // @ts-ignore close && closeGradeDialog(); } else if (endTime < new Date().getTime()) { clearInterval(checkExist); console.log('not found in specified time.'); return; } else { console.log('waiting for element to be present…'); } }, 100); } function liveUpdate() { let totalGrade = document.querySelector('#saertosashualo span'); totalGrade && totalGrade.click(); waitUntilAvgPresent( '#cnt > div.div_container_grades > table > tbody > tr > td:nth-child(4)', totalGrade, true ); } let ftSpan = document.createElement('span'); document.querySelector('#ft')?.appendChild(ftSpan); function gradeSpier() { $('#pageBody')?.prepend(` <form id="gmSomeID"> <input type="search" placeholder="Grade Viewer - User" list="datalistOptions" id="gminput"> <button id="gmview">View</button> <datalist id='datalistOptions'> </form> `); document.querySelector('#gmview').addEventListener('click', (e) => { e.preventDefault(); let val = document.querySelector('#gminput').value; if (val) { // @ts-ignore gradeclick(val, -1); waitUntilAvgPresent( '#cnt > div.div_container_grades > table > tbody > tr > td:nth-child(4)', ftSpan ); } }); } function attendanceSpier() { $('#pageBody')?.prepend(` <form id="gmSomeID2"> <input type="search" placeholder="Attendance Viewer - User" list='datalistOptions' id="gminput2"> <input type="search" placeholder="Subject ID" list='datalistOptionsAttend' id="gminput3"> <button id="gmview2">View</button> <datalist id='datalistOptionsAttend'> </form> `); document.querySelector('#gmview2').addEventListener('click', (e) => { e.preventDefault(); let val = document.querySelector('#gminput2').value; let val2 = document.querySelector('#gminput3').value; // @ts-ignore val && val2 && attendanceclick(val, val2); }); } const currentPage = window.location.pathname; if ( currentPage === '/Parent/Index' || currentPage === '/Parent/AllSubjects' ) { if (settings.changeGrade) { newGrade(settings.changeGrade); } if (settings.changeAttendance) { newAttendance(settings.changeAttendance); } if (settings.liveGradeUpdate) { liveUpdate(); } if (settings.attendanceViewer || settings.gradeViewer) { const main = async () => { try { const options = { method: 'POST', headers: { accept: 'application/json, text/javascript, */*; q=0.01', 'content-type': 'application/json' }, body: '{"pageSize":1000,"filter":"","initValue":null}' }; const req = await fetch( 'https://eservices.schoolbook.ge/SchoolBook/SchoolPersonsList', options ); const res = await req.json(); res['mas'].forEach((val) => { $('#datalistOptions')?.append( `<option value="${val.value}" label="${val.text}">` ); }); document .querySelectorAll( '#tablestatistic > div.owl-carousel.tablestat.owl-loaded.owl-drag > div.owl-stage-outer > div > div:not(.cloned) > div > div' ) .forEach((val) => { $('#datalistOptionsAttend')?.append( `<option value="${val.id.replace('sagani_', '')}" label="${ val.querySelector('.subject_name').innerText }">` ); }); } catch (error) { console.error(error); } }; main(); if (settings.gradeViewer) { gradeSpier(); } if (settings.attendanceViewer) { attendanceSpier(); } } } if (currentPage === '/Parent/Messages' && settings.hideComments) { removeComments(); } })();