-
-
Save Verssae/0ed510986e87a8360965daaef3608861 to your computer and use it in GitHub Desktop.
| /* | |
| Hanyang Univ. a script for skipping safetyedu courses | |
| http://safetyedu.hanyang.ac.kr/ | |
| [교육 영상 스킵] | |
| 1. '수강하기' 버튼을 눌러 안전교육 창을 띄운다. | |
| 2. 개발자도구(F12 버튼을 눌러)를 열어 'console' 탭에 이동해 아래 스크립트를 붙여넣는다. | |
| 3. 6과목에 대해 반복한다. | |
| ref: https://kysgh2.tistory.com/113 | |
| */ | |
| var currentPage = nowPageNum; | |
| function goNextPage() { | |
| if (currentPage < totalPageNum) { | |
| opener.PageMove(currentPage); | |
| console.log(`${currentPage} 페이지를 수강완료했습니다.`); | |
| currentPage += 1; | |
| setTimeout(function () { | |
| goNextPage(); | |
| }, 100); | |
| } else { | |
| opener.PageMove(currentPage); | |
| console.log('강의 수강이 완료되었습니다!'); | |
| setTimeout(function () { | |
| window.close(); | |
| }, 200); | |
| } | |
| } | |
| setTimeout(function () { | |
| goNextPage(); | |
| }, 100) | |
| /* | |
| [퀴즈 스킵] | |
| 1. 6과목을 다 듣고 '평가하기' 버튼을 누른다. | |
| 2. 개발자도구(F12 버튼을 눌러)를 열어 'console' 탭에 이동해 아래 스크립트를 붙여넣는다. | |
| */ | |
| SetExamAfeter(); | |
| let answers = Array.from({length: questionCountInExam}, (x,i) => document.getElementById("qustionCorrectNo_" + i).value); | |
| SetExamBefore(); | |
| for (let i=0; i<questionCountInExam; i++) { | |
| let ls = document.getElementsByName(`qustionAnswerList[${i}].Answer`); | |
| console.log(ls); | |
| ls[answers[i]-1].checked = true; | |
| } | |
| document.getElementById("Exam_btnSave").click(); |
유익한 글이에요.
최근에 본 글 중 가장 퀄리티가 높네요.
유익한 글입니다 감사합니다!
좋은 정보 감사합니다 벌새님
감사합니다.
감사합니다
비정상 방법이라고 초기화 되네요ㅜ
2024년 2학기 도중에 새 엔진이 들어와서 그런지 작동 안하는 강의가 있네요
2024년 2학기 도중에 새 엔진이 들어와서 그런지 작동 안하는 강의가 있네요
document.querySelector('video').playbackRate = 16;
동영상 전용이여서 그런가봅니다. 동영상에 최대 16배속 걸어두면 빠르게 해결됩니다.
동영상 전용 해결방법
const formData = new FormData();
formData.append('scheduleMemberProgressNo', '1361183(예시)'); // 영상 링크중에 scheduleMemberProgressNo 뒤에 번호 넣으시면 됩니다
formData.append('currentTime', '1');
formData.append('isEnd', 'true');
fetch('https://safetyedu.hanyang.ac.kr/Edu/AviProcessCheck', {
method: 'POST',
body: formData
})
.then(response => response.text())
.then(data => {
console.log('서버 응답:', data);
})
.catch(error => {
console.error('에러 발생:', error);
});
"서버 응답: {"IsSuccess":true,"Msg":""}"
요렇게 뜨시면 나가시고 새로고침 하면 적용됩니다.
몇번 테스트해보긴 했는데 일단 저는 잘 작동했습니다.
동영상 전용(2025 ver.) + 2학기 수정
const urlParams = new URLSearchParams(window.location.search);
const scheduleMemberProgressNo = urlParams.get('scheduleMemberProgressNo');
const formData = new FormData();
formData.append('scheduleMemberProgressNo', scheduleMemberProgressNo);
formData.append('currentTime', '1');
formData.append('isEnd', 'true');
fetch('https://safetyedu.hanyang.ac.kr/Edu/AviProcessCheck', {
method: 'POST',
mode: 'no-cors',
body: formData
})
.then(response => {
console.log('요청 전송 완료:', response);
return response.text();
})
.then(data => {
console.log('서버 응답:', data);
})
.catch(error => {
console.error('에러 발생:', error);
});스크립트 입력 후 팝업 닫고 새로고침하면 적용됩니다
감사합니다:)
동영상 전용(2026 ver.)
(function() {
// 1. 확인된 번호 입력
const myNo = '1632055';
const params = new URLSearchParams();
params.append('scheduleMemberProgressNo', myNo);
params.append('currentTime', '2500'); // 40분 분량에 맞춰 2500초로 설정
params.append('isEnd', 'true'); // 수강 완료를 위해 true로 변경
params.append('isMobile', 'false'); // 확인하신 필수값 추가
console.log(`[${myNo}] 번 과목 최종 정밀 요청 중...`);
fetch('/ushm/edu/contentsViewAviProcessCheckSub.do', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest'
},
body: params
})
.then(response => {
console.log('HTTP 상태 코드:', response.status);
return response.text();
})
.then(data => {
console.log("서버 응답 결과:", data);
// 응답에 "success"나 "true"가 포함되어 있는지 확인
if (data.includes("true") || response.status === 200) {
console.log("%c ✅ 수강 완료 처리에 성공한 것으로 보입니다!", "color: #2ecc71; font-weight: bold; font-size: 14px;");
alert("처리가 완료되었습니다. 메인 페이지를 새로고침하세요!");
}
})
.catch(error => {
console.error("⚠️ 네트워크 에러:", error);
});
})();
스크립트 입력 후 팝업 닫고 새로고침하면 적용됩니다!
(async function simulateRealProgress() {
'use strict';
// ---------- 1. 自动收集页面关键参数 ----------
const paramGetters = [
() => document.querySelector('input[name="scheduleMemberProgressNo"]')?.value,
() => document.querySelector('input[name="scheduleNo"]')?.value,
() => document.querySelector('input[name="courseNo"]')?.value,
() => document.querySelector('input[name="contentNo"]')?.value,
() => document.querySelector('input[name="memberNo"]')?.value,
() => document.querySelector('meta[name="csrf-token"]')?.content,
() => window.csrfToken,
() => window._csrf,
() => {
const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);
return match ? match[1] : null;
}
];
const baseParams = {};
paramGetters.forEach(getter => {
try {
const val = getter();
if (val) {
const name = getter.toString().match(/name="([^"]+)"/)?.[1] || 'csrfToken';
baseParams[name] = val;
}
} catch (e) {}
});
// 硬编码的 scheduleMemberProgressNo(如果自动抓取失败则使用用户提供的)
const scheduleMemberProgressNo = baseParams.scheduleMemberProgressNo || '1632055';
console.log(' 基础参数:', baseParams);
// ---------- 2. 获取视频元素并计算总时长 ----------
const video = document.querySelector('video');
if (!video) {
console.error('未找到 video 元素,无法继续');
return;
}
// 确保视频元数据已加载
if (video.readyState < 1) {
console.log(' 等待视频元数据加载...');
await new Promise(resolve => {
video.addEventListener('loadedmetadata', resolve, { once: true });
video.load();
});
}
const totalDuration = Math.ceil(video.duration);
console.log(`视频总时长: ${totalDuration} 秒 (${Math.floor(totalDuration/60)}分${totalDuration%60}秒)`);
// ---------- 3. 模拟播放行为(触发视频事件,绕过部分检测) ----------
console.log('模拟播放行为...');
video.currentTime = 0;
video.play().catch(() => {}); // 忽略自动播放限制错误
// 等待一小段时间,让浏览器记录“播放”动作
await new Promise(r => setTimeout(r, 1500));
video.pause();
// ---------- 4. 分步上报进度(模拟真实观看) ----------
const steps = 1; // 上报次数,越多越真实
const stepTime = totalDuration / steps;
for (let i = 1; i <= steps; i++) {
const currentTime = Math.floor(stepTime * i);
const isEnd = (i === steps); // 最后一次才标记完成
video.currentTime = currentTime;
video.dispatchEvent(new Event('timeupdate', { bubbles: true }));
// 构造请求参数
const formData = new URLSearchParams();
formData.append('scheduleMemberProgressNo', scheduleMemberProgressNo);
formData.append('currentTime', currentTime);
formData.append('studyTime', currentTime);
formData.append('progressRate', Math.floor((currentTime / totalDuration) * 100));
formData.append('isEnd', isEnd ? 'true' : 'false');
formData.append('isMobile', 'false');
// 追加自动抓取的其他参数
Object.entries(baseParams).forEach(([key, val]) => {
if (!formData.has(key)) formData.append(key, val);
});
// 发送请求
console.log(`第 ${i}/${steps} 次上报: 进度 ${currentTime}秒 / ${totalDuration}秒, 完成=${isEnd}`);
const response = await fetch('/ushm/edu/contentsViewAviProcessCheckSub.do', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest',
...(baseParams.csrfToken && { 'X-CSRF-TOKEN': baseParams.csrfToken })
},
credentials: 'include',
body: formData
});
const text = await response.text();
console.log(` 响应: ${text.substring(0, 100)}`);
const delay = 2000 + Math.floor(Math.random() * 3000);
await new Promise(r => setTimeout(r, delay));
}
// ---------- 5. 最终完成标记(确保 isEnd=true 发送一次) ----------
console.log('发送最终完成确认...');
const finalParams = new URLSearchParams();
finalParams.append('scheduleMemberProgressNo', scheduleMemberProgressNo);
finalParams.append('currentTime', totalDuration);
finalParams.append('isEnd', 'true');
finalParams.append('isMobile', 'false');
Object.entries(baseParams).forEach(([k, v]) => { if (!finalParams.has(k)) finalParams.append(k, v); });
await fetch('/ushm/edu/contentsViewAviProcessCheckSub.do', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest' },
credentials: 'include',
body: finalParams
});
console.log('%c The simulation of the learning process has completed! Refresh the page to check if the progress has reached 100%.', 'color: green; font-weight: bold; font-size: 14px');
alert('The script has finished running. Please refresh the page to see the results.');
})();
좋은 정보 감사합니다.