[2-13~21] 이미지 파일 클립길이, 오버레이, 트랜지션 처리 수정
This commit is contained in:
Binary file not shown.
146
DIC_2505B.json
146
DIC_2505B.json
@@ -115,10 +115,10 @@
|
|||||||
"value": "GungsuhChe",
|
"value": "GungsuhChe",
|
||||||
"point": 2,
|
"point": 2,
|
||||||
"desc": {
|
"desc": {
|
||||||
"돋움체":"DotumChe",
|
"돋움체": "DotumChe",
|
||||||
"궁서체":"GungsuhChe",
|
"궁서체": "GungsuhChe",
|
||||||
"굴림체":"GulimChe",
|
"굴림체": "GulimChe",
|
||||||
"휴먼옛체":"YetR"
|
"휴먼옛체": "YetR"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"16": {
|
"16": {
|
||||||
@@ -181,7 +181,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"2": {
|
"2": {
|
||||||
"desc": "videoStartTime 항목은 동영상파일>자막>시작시간 문항의 정답을 작성",
|
|
||||||
"videoStartTime": 170,
|
"videoStartTime": 170,
|
||||||
"openingStartTime": 0,
|
"openingStartTime": 0,
|
||||||
"1": {
|
"1": {
|
||||||
@@ -206,7 +205,7 @@
|
|||||||
"desc": "100당 1배속 / 130 = 1.3배속"
|
"desc": "100당 1배속 / 130 = 1.3배속"
|
||||||
},
|
},
|
||||||
"3": {
|
"3": {
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{videoClipIndex}']",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']",
|
||||||
"type": "startEnd",
|
"type": "startEnd",
|
||||||
"media": "동영상.mp4",
|
"media": "동영상.mp4",
|
||||||
"value": {
|
"value": {
|
||||||
@@ -217,7 +216,7 @@
|
|||||||
"desc": "시작시간과 재생시간 정답값 입력, 3번문항은 '동영상.mp4' 클립의 길이를 확인하는 문항이므로 media는 수정할 필요가 없다."
|
"desc": "시작시간과 재생시간 정답값 입력, 3번문항은 '동영상.mp4' 클립의 길이를 확인하는 문항이므로 media는 수정할 필요가 없다."
|
||||||
},
|
},
|
||||||
"4": {
|
"4": {
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{videoClipIndex}']//CRFilter",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
"type": "effect",
|
"type": "effect",
|
||||||
"media": "동영상.mp4",
|
"media": "동영상.mp4",
|
||||||
"value": {
|
"value": {
|
||||||
@@ -273,111 +272,110 @@
|
|||||||
"search": "청량하고 시원한 폭포",
|
"search": "청량하고 시원한 폭포",
|
||||||
"type": "video.StartTime",
|
"type": "video.StartTime",
|
||||||
"value": 170,
|
"value": 170,
|
||||||
"point": 2
|
"point": 2,
|
||||||
|
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
||||||
},
|
},
|
||||||
"11": {
|
"11": {
|
||||||
"ele": "",
|
"ele": "",
|
||||||
"search": "청량하고 시원한 폭포",
|
"search": "청량하고 시원한 폭포",
|
||||||
"type": "video.Length",
|
"type": "video.Length",
|
||||||
"value": 150,
|
"value": 150,
|
||||||
"point": 2
|
"point": 2,
|
||||||
|
"desc": "내부적으로 자막의 시작시간과 길이를 계산"
|
||||||
},
|
},
|
||||||
"12": {
|
"12": {
|
||||||
"existEle": "//CRClip[@Path='동영상.mp4']",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Mute",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='동영상.mp4']/preceding-sibling::*)]/@Mute",
|
"type": "Mute",
|
||||||
"type": "searchIndex",
|
"media": "동영상.mp4",
|
||||||
"value": "1",
|
"value": "1",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"13": {
|
"13": {
|
||||||
"existEle": "//CRClip[@Path='{image}'] | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/@Length",
|
"type": "imageLength",
|
||||||
"image": "이미지2.jpg",
|
"media": "이미지2.jpg",
|
||||||
"type": "searchIndex",
|
|
||||||
"value": "150",
|
"value": "150",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"14": {
|
"14": {
|
||||||
"type": "multi",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]//CRFilter/@*[name()='ID' or name()='VID102']",
|
"type": "imageOverlay",
|
||||||
"image": "이미지2.jpg",
|
"media": "이미지2.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"103",
|
"ID": "103",
|
||||||
"7"
|
"VID102": "7"
|
||||||
],
|
},
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"15": {
|
"15": {
|
||||||
"type": "multi",
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
"ele": "//CRTransFilter[@ClipIndex=count(//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/preceding-sibling::CRTrackClip)][@Type='2']/@*[name()='ID' or name()='Range' or name()='Type']",
|
"type": "clipTransition",
|
||||||
"image": "이미지2.jpg",
|
"media": "이미지2.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"11",
|
"ID": "11",
|
||||||
"500:530",
|
"Range": "500:530",
|
||||||
"2"
|
"Type": "2"
|
||||||
],
|
},
|
||||||
"point": 2,
|
"point": 2,
|
||||||
"desc": "오버랩일 경우 XPATH구문에서 Type속성값 16으로 변경, 그리고 ClipIndex값은 트랜지션이 끝나는 지점 이미지의 ClipIndex값을 가지게 되어 다음 순서의 이미지로 변경해주어야한다."
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
},
|
},
|
||||||
"16": {
|
"16": {
|
||||||
"existEle": "//CRClip[@Path='{image}'] | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/@Length",
|
"type": "imageLength",
|
||||||
"image": "이미지3.jpg",
|
"media": "이미지3.jpg",
|
||||||
"type": "searchIndex",
|
|
||||||
"value": "150",
|
"value": "150",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"17": {
|
"17": {
|
||||||
"type": "multi",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]//CRFilter/@*[name()='ID' or name()='VID102']",
|
"type": "imageOverlay",
|
||||||
"image": "이미지3.jpg",
|
"media": "이미지3.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"184",
|
"ID": "184",
|
||||||
"30"
|
"VID102": "30"
|
||||||
],
|
},
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"18": {
|
"18": {
|
||||||
"type": "multi",
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
"ele": "//CRTransFilter[@ClipIndex=count(//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/preceding-sibling::CRTrackClip)][@Type='2']/@*[name()='ID' or name()='Range' or name()='Type']",
|
"type": "clipTransition",
|
||||||
"image": "이미지3.jpg",
|
"media": "이미지3.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"19",
|
"ID": "19",
|
||||||
"650:680",
|
"Range": "650:680",
|
||||||
"2"
|
"Type": "2"
|
||||||
],
|
},
|
||||||
"point": 2,
|
"point": 2,
|
||||||
"desc": "오버랩일 경우 XPATH구문에서 Type속성값 16으로 변경, 그리고 ClipIndex값은 트랜지션이 끝나는 지점 이미지의 ClipIndex값을 가지게 되어 다음 순서의 이미지로 변경해주어야한다."
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
},
|
},
|
||||||
"19": {
|
"19": {
|
||||||
"existEle": "//CRClip[@Path='{image}'] | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']/@Length",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/@Length",
|
"type": "imageLength",
|
||||||
"image": "이미지1.jpg",
|
"media": "이미지1.jpg",
|
||||||
"type": "searchIndex",
|
|
||||||
"value": "180",
|
"value": "180",
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"20": {
|
"20": {
|
||||||
"type": "multi",
|
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter",
|
||||||
"ele": "//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]//CRFilter/@*[name()='ID' or name()='VID102']",
|
"type": "imageOverlay",
|
||||||
"image": "이미지1.jpg",
|
"media": "이미지1.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"67",
|
"ID": "67",
|
||||||
"30"
|
"VID102": "30"
|
||||||
],
|
},
|
||||||
"point": 2
|
"point": 2
|
||||||
},
|
},
|
||||||
"21": {
|
"21": {
|
||||||
"type": "multi",
|
"ele": "//CRTransFilter[@ClipIndex='{CRTrackClipIndex}']",
|
||||||
"ele": "//CRTransFilter[@ClipIndex=count(//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='{image}']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='{image}']/../preceding-sibling::CRClip)][1]/preceding-sibling::CRTrackClip)][@Type='2']/@*[name()='ID' or name()='Range' or name()='Type']",
|
"type": "clipTransition",
|
||||||
"image": "이미지1.jpg",
|
"media": "이미지1.jpg",
|
||||||
"value": [
|
"value": {
|
||||||
"10",
|
"ID": "10",
|
||||||
"800:860",
|
"Range": "800:860",
|
||||||
"2"
|
"Type": "2"
|
||||||
],
|
},
|
||||||
"point": 2,
|
"point": 2,
|
||||||
"desc": "오버랩일 경우 XPATH구문에서 Type속성값 16으로 변경, 그리고 ClipIndex값은 트랜지션이 끝나는 지점 이미지의 ClipIndex값을 가지게 되어 다음 순서의 이미지로 변경해주어야한다."
|
"desc": "오버랩일 경우 Type속성값 16으로 변경"
|
||||||
},
|
},
|
||||||
"22": {
|
"22": {
|
||||||
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr/@Name",
|
"ele": "//CROwneUnit[{subtitleIndex}]/CRCUnitArr/@Name",
|
||||||
@@ -434,7 +432,7 @@
|
|||||||
"point": 3
|
"point": 3
|
||||||
},
|
},
|
||||||
"28": {
|
"28": {
|
||||||
"ele":"{search}",
|
"ele": "{search}",
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "openingStartTime",
|
"type": "openingStartTime",
|
||||||
"value": 0,
|
"value": 0,
|
||||||
@@ -442,7 +440,7 @@
|
|||||||
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
"desc": "오프닝자막의 시작시간 value 속성만 수정"
|
||||||
},
|
},
|
||||||
"29": {
|
"29": {
|
||||||
"ele":"{search}",
|
"ele": "{search}",
|
||||||
"search": "전통 공원 (Traditional Park)",
|
"search": "전통 공원 (Traditional Park)",
|
||||||
"type": "openingLength",
|
"type": "openingLength",
|
||||||
"value": 120,
|
"value": 120,
|
||||||
|
|||||||
282
psdExport_2.js
282
psdExport_2.js
@@ -9,6 +9,8 @@ const { DOMParser } = require('xmldom');
|
|||||||
const findSimilarString = require('./findSimilarString');
|
const findSimilarString = require('./findSimilarString');
|
||||||
const getGpdpScore = require('./gpdpScoring.js');
|
const getGpdpScore = require('./gpdpScoring.js');
|
||||||
const getToday = require('./getToday.js');
|
const getToday = require('./getToday.js');
|
||||||
|
const { userInfo } = require('os');
|
||||||
|
const { get } = require('http');
|
||||||
const todayDate = getToday();
|
const todayDate = getToday();
|
||||||
|
|
||||||
const examRound = '2505';
|
const examRound = '2505';
|
||||||
@@ -172,32 +174,39 @@ outputExcelFiles.forEach((outputFile, index) => {
|
|||||||
// scoring.json 파일 내에 있는 type에 따라 비교하는 방식이 달라짐
|
// scoring.json 파일 내에 있는 type에 따라 비교하는 방식이 달라짐
|
||||||
// 채점 결과를 scoringResultList 배열에 저장
|
// 채점 결과를 scoringResultList 배열에 저장
|
||||||
function getGmepScore(gmepData, scoringJson, index) {
|
function getGmepScore(gmepData, scoringJson, index) {
|
||||||
function compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, tolerance = 0) {
|
function compareAndScore(user, right, point, key, scoringResult, options = {}) {
|
||||||
let score = 0;
|
let score = 0;
|
||||||
|
let isEqual = false;
|
||||||
|
|
||||||
let isEqual;
|
const {
|
||||||
|
tolerance = 0, // 숫자 비교 시 허용 오차
|
||||||
|
type = 'auto', // 'auto' | 'number[]' | 'string[]' | 'object' | 'primitive'
|
||||||
|
} = options;
|
||||||
|
|
||||||
if (Array.isArray(rightAnswer) && Array.isArray(userAnswer)) {
|
if (type === 'force-correct') {
|
||||||
// 배열 길이 같아야 비교 가능
|
isEqual = true;
|
||||||
if (rightAnswer.length === userAnswer.length) {
|
|
||||||
isEqual = rightAnswer.every((val, idx) => Math.abs(val - userAnswer[idx]) <= tolerance);
|
|
||||||
} else {
|
|
||||||
isEqual = false;
|
|
||||||
}
|
}
|
||||||
} else if (typeof rightAnswer === "object" && typeof userAnswer === "object") {
|
else if (Array.isArray(right) && Array.isArray(user)) {
|
||||||
// 객체일 때는 기존 방식 유지 (원하면 별도 로직 추가 가능)
|
if (right.length === user.length) {
|
||||||
isEqual = JSON.stringify(userAnswer) === JSON.stringify(rightAnswer);
|
if (type === 'number[]' || (type === 'auto' && typeof right[0] === 'number')) {
|
||||||
|
isEqual = right.every((val, idx) => Math.abs(val - user[idx]) <= tolerance);
|
||||||
|
} else if (type === 'string[]' || (type === 'auto' && typeof right[0] === 'string')) {
|
||||||
|
isEqual = right.every((val, idx) => val === user[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (type === 'object' || (type === 'auto' && typeof right === 'object' && typeof user === 'object')) {
|
||||||
|
isEqual = JSON.stringify(user) === JSON.stringify(right);
|
||||||
} else {
|
} else {
|
||||||
isEqual = userAnswer == rightAnswer;
|
isEqual = user == right; // primitive 비교
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEqual) {
|
if (isEqual) {
|
||||||
score = point;
|
score = point;
|
||||||
console.log('작성답안: ', userAnswer);
|
console.log('작성답안: ', user);
|
||||||
console.log('>⭕ 정답: ', rightAnswer);
|
console.log('>⭕ 정답: ', right);
|
||||||
} else {
|
} else {
|
||||||
console.log('작성답안: ', userAnswer);
|
console.log('작성답안: ', user);
|
||||||
console.log('>❌ 오답: ', rightAnswer);
|
console.log('>❌ 오답: ', right);
|
||||||
}
|
}
|
||||||
|
|
||||||
scoringResult[key] = score;
|
scoringResult[key] = score;
|
||||||
@@ -240,16 +249,9 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc);
|
const mediaPathList = xpath.select("//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path", gmepXmlDoc);
|
||||||
|
|
||||||
// "동영상.mp4"의 clipIndex를 구함
|
// "동영상.mp4"의 clipIndex를 구함
|
||||||
const videoClipIndex = mediaPathList.findIndex(mediaPath => mediaPath.value === mediaName);
|
|
||||||
let xpathList = [ele, ele2];
|
|
||||||
xpathList = xpathList.map(e => e ? e
|
|
||||||
.replace(/{videoClipIndex}/g, videoClipIndex)
|
|
||||||
: e
|
|
||||||
);
|
|
||||||
[ele, ele2] = xpathList;
|
|
||||||
// clipIndex가 -1이면 해당 미디어가 존재하지 않는 것
|
// clipIndex가 -1이면 해당 미디어가 존재하지 않는 것
|
||||||
|
const crclipIndex = mediaPathList.findIndex(mediaPath => mediaPath.value === mediaName);
|
||||||
return videoClipIndex;
|
return crclipIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 자막 텍스트로 자막클립인덱스 반환
|
// 자막 텍스트로 자막클립인덱스 반환
|
||||||
@@ -265,7 +267,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('🟢 자막 텍스트로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
// console.log('🟢 자막 텍스트로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
||||||
return subtitleClipIndex;
|
return subtitleClipIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,7 +288,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('🟡 자막 순서로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
// console.log('🟡 자막 순서로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
||||||
return subtitleClipIndex;
|
return subtitleClipIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,7 +311,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('🟠 자막 시작시간으로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
// console.log('🟠 자막 시작시간으로 검색한 CROwneUnit 인덱스 : ', subtitleClipIndex);
|
||||||
return subtitleClipIndex;
|
return subtitleClipIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -327,11 +329,11 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
total += length;
|
total += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("🔵 자막 구간 시작시간 : ", cumulativeLengths);
|
// console.log("🔵 자막 구간 시작시간 : ", cumulativeLengths);
|
||||||
return cumulativeLengths;
|
return cumulativeLengths;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCrtrackClipIndex(clipIndex) {
|
function getTextTrackClipIndex(clipIndex) {
|
||||||
const crTrackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc);
|
const crTrackClips = xpath.select(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip`, gmepXmlDoc);
|
||||||
|
|
||||||
let index = null;
|
let index = null;
|
||||||
@@ -344,37 +346,41 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getVideoTrackClipIndex(clipIndex) {
|
||||||
|
const crTrackClips = xpath.select(`//CRTrackList[@Name='비디오1']/CRTrackClip`, gmepXmlDoc);
|
||||||
|
|
||||||
|
let index = null;
|
||||||
|
for (let i = 0; crTrackClips.length; i++) {
|
||||||
|
if (clipIndex == parseInt(crTrackClips[i].getAttribute('ClipIndex'), 10)) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
let ele = scoringData[key].ele;
|
let ele = scoringData[key].ele;
|
||||||
let ele2 = scoringData[key].ele2;
|
let ele2 = scoringData[key].ele2;
|
||||||
let ele3 = scoringData[key].ele3;
|
let ele3 = scoringData[key].ele3;
|
||||||
let existEle = scoringData[key].existEle;
|
let existEle = scoringData[key].existEle;
|
||||||
const rightAnswer = scoringData[key].value;
|
const rightAnswer = scoringData[key].value;
|
||||||
const point = scoringData[key].point;
|
const point = scoringData[key].point;
|
||||||
const type = scoringData[key].type;
|
const type = scoringData[key].type ? scoringData[key].type : '';
|
||||||
let search = scoringData[key].search;
|
let search = scoringData[key].search;
|
||||||
const media = scoringData[key].media;
|
const media = scoringData[key].media;
|
||||||
|
|
||||||
const videoStartTime = scoringData.videoStartTime;
|
const videoStartTime = scoringData.videoStartTime;
|
||||||
const openingStartTime = scoringData.openingStartTime;
|
const openingStartTime = scoringData.openingStartTime;
|
||||||
|
|
||||||
const image = scoringData[key].image;
|
const image = scoringData[key].image;
|
||||||
|
|
||||||
|
let userAnswer = null;
|
||||||
|
|
||||||
console.log(`example number: ${key}`)
|
console.log(`example number: ${key}`)
|
||||||
|
|
||||||
// xpath 전처리
|
// xpath 전처리
|
||||||
const trackClipNode = getTrackClipNode(gmepXmlDoc, type, videoStartTime, openingStartTime);
|
const trackClipNode = getTrackClipNode(gmepXmlDoc, type, videoStartTime, openingStartTime);
|
||||||
const subtitleIndex = trackClipNode ? parseInt(trackClipNode.getAttribute('ClipIndex'), 10) + 1 : null;
|
const subtitleIndex = trackClipNode ? parseInt(trackClipNode.getAttribute('ClipIndex'), 10) + 1 : null;
|
||||||
const textClipIndex = getTextClipIndex(gmepXmlDoc, search);
|
const textClipIndex = getTextClipIndex(gmepXmlDoc, search);
|
||||||
// const typeToOrderMap = {
|
|
||||||
// opening: 1,
|
|
||||||
// openingStartTime: 1,
|
|
||||||
// openingLength: 1,
|
|
||||||
// openingText: 1,
|
|
||||||
// video: 2,
|
|
||||||
// videoStartTime: 2,
|
|
||||||
// videoLength: 2,
|
|
||||||
// videoText: 2,
|
|
||||||
// };
|
|
||||||
// const subtitleOrder = typeToOrderMap[type] ?? null;
|
|
||||||
const subtitleOrder = type.includes('opening') ? 1 : type.includes('video') ? 2 : null;
|
const subtitleOrder = type.includes('opening') ? 1 : type.includes('video') ? 2 : null;
|
||||||
const startTime = type === 'video' ? videoStartTime : type === 'opening' ? openingStartTime : null;
|
const startTime = type === 'video' ? videoStartTime : type === 'opening' ? openingStartTime : null;
|
||||||
|
|
||||||
@@ -408,10 +414,6 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log("🚀 ~ getGmepScore ~ ele:", ele)
|
|
||||||
// console.log("🚀 ~ getGmepScore ~ ele2:", ele2)
|
|
||||||
// console.log("🚀 ~ getGmepScore ~ ele3:", ele3)
|
|
||||||
|
|
||||||
// xpath
|
// xpath
|
||||||
if (ele === 'none') {
|
if (ele === 'none') {
|
||||||
scoringResult[key] = "확인필요";
|
scoringResult[key] = "확인필요";
|
||||||
@@ -425,7 +427,7 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
else if (type == "oneAnswer") {
|
else if (type == "oneAnswer") {
|
||||||
const result = xpath.select1(ele, gmepXmlDoc);
|
const result = xpath.select1(ele, gmepXmlDoc);
|
||||||
|
|
||||||
let userAnswer = {};
|
// userAnswer = {};
|
||||||
if ("speed" in rightAnswer) {
|
if ("speed" in rightAnswer) {
|
||||||
userAnswer = {
|
userAnswer = {
|
||||||
"speed": result ? result.value : null,
|
"speed": result ? result.value : null,
|
||||||
@@ -437,8 +439,8 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
|
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
// [3-1] 문항
|
|
||||||
|
|
||||||
|
// [3-1] 문항
|
||||||
else if (type == "mediaOrder") {
|
else if (type == "mediaOrder") {
|
||||||
// 미디어 순서를 저장할 배열
|
// 미디어 순서를 저장할 배열
|
||||||
const mediaOrderList = [];
|
const mediaOrderList = [];
|
||||||
@@ -466,50 +468,52 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const userAnswer = mediaOrderList;
|
const userAnswer = mediaOrderList;
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
|
type: 'string[]'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == "startEnd") {
|
else if (type == "startEnd") {
|
||||||
const videoClipIndex = getClipIndexByMediaPath(media);
|
const crclipIndex = getClipIndexByMediaPath(media);
|
||||||
|
|
||||||
// 해당 미디어가 없을경우 clipIndex값 -1
|
// 해당 미디어가 없을경우 clipIndex값 -1
|
||||||
if (videoClipIndex == -1) {
|
if (crclipIndex == -1) {
|
||||||
scoringResult[key] = 0;
|
userAnswer = null;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// //CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='동영상.mp4'] 요소를 찾음
|
//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='동영상.mp4'] 요소를 찾음
|
||||||
const CRTrackClipNode = xpath.select1(ele, gmepXmlDoc);
|
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
if (!CRTrackClipNode) {
|
const crTrackClip = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
scoringResult[key] = 0;
|
if (!crTrackClip) {
|
||||||
continue;
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// CRTrackClip 요소의 Pos(시작시간)과 Length(재생길이)를 구함
|
// CRTrackClip 요소의 Pos(시작시간)과 Length(재생길이)를 구함
|
||||||
const pos = xpath.select1('@Pos', CRTrackClipNode);
|
const pos = xpath.select1('@Pos', crTrackClip);
|
||||||
const length = xpath.select1('@Length', CRTrackClipNode);
|
const length = xpath.select1('@Length', crTrackClip);
|
||||||
const userAnswer = { start: pos.value, end: length.value }
|
userAnswer = { start: pos.value, end: length.value }
|
||||||
|
}
|
||||||
|
}
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
// 동영상 클립 이펙트 [2-4]
|
||||||
else if (type == "effect") {
|
// 이미지 클립 오버레이 [2-14, 17, 20]
|
||||||
const videoClipIndex = getClipIndexByMediaPath(media);
|
else if (type == "effect" || type === "imageOverlay") {
|
||||||
if (videoClipIndex == -1) {
|
const crclipIndex = getClipIndexByMediaPath(media);
|
||||||
scoringResult[key] = 0;
|
// 해당 미디어가 없을경우 clipIndex값 -1
|
||||||
continue;
|
if (crclipIndex == -1) {
|
||||||
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{videoClipIndex}']//CRFilter
|
//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='{CRClipIndex}']//CRFilter
|
||||||
const CRFilterNode = xpath.select1(ele, gmepXmlDoc);
|
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
if (!CRFilterNode) {
|
const crFilter = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
scoringResult[key] = 0;
|
if (!crFilter) {
|
||||||
continue;
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const userAnswer = {}
|
userAnswer = {}
|
||||||
const attributes = CRFilterNode.attributes;
|
const attributes = crFilter.attributes;
|
||||||
|
|
||||||
// rightAnswer의 key값을 순회하면서
|
// rightAnswer의 key값을 순회하면서
|
||||||
// CRFilterNode의 속성명과 일치하는 값을 userAnswer에 저장
|
// CRFilterNode의 속성명과 일치하는 값을 userAnswer에 저장
|
||||||
@@ -523,16 +527,112 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 자막관련 type검사하는 구문을 opening포함 video포함으로 변경
|
// 동영상 클립 트랜지션 [2-15, 18, 21]
|
||||||
// 6/16(월)시작 지점
|
else if (type === 'clipTransition') {
|
||||||
// 1. JSON파일 10,11번 처럼 변경
|
const crclipIndex = getClipIndexByMediaPath(media);
|
||||||
else if (type.includes('opening') || type.includes('video')) {
|
let crtrackClipIndex = getVideoTrackClipIndex(crclipIndex);
|
||||||
function toHexColor(value) {
|
|
||||||
|
|
||||||
|
if (crtrackClipIndex == -1) {
|
||||||
|
userAnswer = null;
|
||||||
}
|
}
|
||||||
// else if (type === 'openingStartTime' || type === 'openingLength'
|
else {
|
||||||
// || type === 'videoStartTime' || type === 'videoLength') {
|
// 트랜지션 위치
|
||||||
|
// - 앞으로 이동 : Type = '1'
|
||||||
|
// - 뒤로 이동 : Type = '2'
|
||||||
|
// - 오버랩 : Type = '16'
|
||||||
|
// 트랜지션 위치가 오버랩 일 경우 ( Type 속성이 16인 경우 )
|
||||||
|
// 적용된 이미지(ClipIndex속성값은) 끝나는 지점의 이미지로 적용된다
|
||||||
|
if (rightAnswer['Type'] === '16') {
|
||||||
|
crtrackClipIndex += 1;
|
||||||
|
}
|
||||||
|
const xpathExpr = ele?.replace(/{CRTrackClipIndex}/g, crtrackClipIndex);
|
||||||
|
const crTransFilter = xpath.select(xpathExpr, gmepXmlDoc);
|
||||||
|
if (!crTransFilter) {
|
||||||
|
userAnswer = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
userAnswer = {};
|
||||||
|
let isMatched = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < crTransFilter.length; i++) {
|
||||||
|
const crTransFilterNode = crTransFilter[i];
|
||||||
|
const attributes = crTransFilterNode.attributes;
|
||||||
|
|
||||||
|
const idAttr = attributes.getNamedItem('ID');
|
||||||
|
const typeAttr = attributes.getNamedItem('Type');
|
||||||
|
const rangeAttr = attributes.getNamedItem('Range');
|
||||||
|
|
||||||
|
const userId = idAttr ? idAttr.value : null;
|
||||||
|
const userType = typeAttr ? typeAttr.value : null;
|
||||||
|
const userRange = rangeAttr ? rangeAttr.value : null;
|
||||||
|
|
||||||
|
userAnswer = {
|
||||||
|
ID: userId,
|
||||||
|
Range: userRange,
|
||||||
|
Type: userType,
|
||||||
|
};
|
||||||
|
|
||||||
|
// ID와 Type은 같고, Range(재생시간 = 종료시간 - 시작시간)도 일치하는지 확인
|
||||||
|
if (
|
||||||
|
userId === rightAnswer.ID &&
|
||||||
|
userType === rightAnswer.Type &&
|
||||||
|
userRange &&
|
||||||
|
rightAnswer.Range
|
||||||
|
) {
|
||||||
|
const [start1, end1] = userRange.split(':').map(Number);
|
||||||
|
const [start2, end2] = rightAnswer.Range.split(':').map(Number);
|
||||||
|
|
||||||
|
const userPlayTime = end1 - start1;
|
||||||
|
const rightPlayTime = end2 - start2;
|
||||||
|
|
||||||
|
if (userPlayTime === rightPlayTime) {
|
||||||
|
isMatched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 일치하지 않으면 null 처리
|
||||||
|
if (!isMatched) {
|
||||||
|
// userAnswer = null;
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
|
type: 'force-correct'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('🟥🟧🟨🟩🟦🟪⬛')
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (type == "Mute") {
|
||||||
|
const crclipIndex = getClipIndexByMediaPath(media);
|
||||||
|
if (crclipIndex == -1) {
|
||||||
|
userAnswer = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
|
const muteStatus = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
|
userAnswer = muteStatus.value;
|
||||||
|
}
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
}
|
||||||
|
// 이미지 클립 길이 [2-13, 16, 19]
|
||||||
|
else if (type === 'imageLength') {
|
||||||
|
const crclipIndex = getClipIndexByMediaPath(media);
|
||||||
|
if (crclipIndex == -1) {
|
||||||
|
userAnswer = null;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const xpathExpr = ele?.replace(/{CRClipIndex}/g, crclipIndex);
|
||||||
|
const imageLength = xpath.select1(xpathExpr, gmepXmlDoc);
|
||||||
|
userAnswer = imageLength.value;
|
||||||
|
}
|
||||||
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (type.includes('opening') || type.includes('video')) {
|
||||||
// 자막의 정보를 이용해 CROwneUnit의 인덱스를 구함
|
// 자막의 정보를 이용해 CROwneUnit의 인덱스를 구함
|
||||||
// 1. 텍스트
|
// 1. 텍스트
|
||||||
// 2. 순서
|
// 2. 순서
|
||||||
@@ -549,8 +649,10 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
const index = indexByText ?? indexByOrder ?? indexByStartTime;
|
const index = indexByText ?? indexByOrder ?? indexByStartTime;
|
||||||
if (index != null) {
|
if (index != null) {
|
||||||
// 자막 시작시간 [2-10] [2-28]
|
// 자막 시작시간 [2-10] [2-28]
|
||||||
|
// <CRTrackClip> 요소들의 시작시간을 갖고 있는 startTimeList를 구하고
|
||||||
|
// 해당 인덱스의 자막 시작시간을 구함
|
||||||
if (type.includes('StartTime')) {
|
if (type.includes('StartTime')) {
|
||||||
const crtrackClipIndex = getCrtrackClipIndex(index)
|
const crtrackClipIndex = getTextTrackClipIndex(index)
|
||||||
const startTimeList = getSubtitleStartTime();
|
const startTimeList = getSubtitleStartTime();
|
||||||
const startTime = startTimeList[crtrackClipIndex];
|
const startTime = startTimeList[crtrackClipIndex];
|
||||||
|
|
||||||
@@ -558,8 +660,9 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult);
|
||||||
}
|
}
|
||||||
// 자막 길이 [2-11] [2-29]
|
// 자막 길이 [2-11] [2-29]
|
||||||
|
// <CRTrackClip> 요소의 Length 속성을 구함
|
||||||
else if (type.includes('Length')) {
|
else if (type.includes('Length')) {
|
||||||
const crtrackClipIndex = getCrtrackClipIndex(index) + 1 // XML 1-based index
|
const crtrackClipIndex = getTextTrackClipIndex(index) + 1 // XML 1-based index
|
||||||
const clipLength = xpath.select1(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[${crtrackClipIndex}]/@Length`, gmepXmlDoc);
|
const clipLength = xpath.select1(`//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[${crtrackClipIndex}]/@Length`, gmepXmlDoc);
|
||||||
|
|
||||||
userAnswer = parseInt(clipLength.value, 10);
|
userAnswer = parseInt(clipLength.value, 10);
|
||||||
@@ -596,7 +699,10 @@ function getGmepScore(gmepData, scoringJson, index) {
|
|||||||
userAnswer = subtitleResult.map(r => r.value);
|
userAnswer = subtitleResult.map(r => r.value);
|
||||||
const errorRange = 0.1;
|
const errorRange = 0.1;
|
||||||
|
|
||||||
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, tolerance = errorRange);
|
totalScore += compareAndScore(userAnswer, rightAnswer, point, key, scoringResult, {
|
||||||
|
tolerance: errorRange,
|
||||||
|
type: 'number[]',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
2
z.xbook
2
z.xbook
@@ -1 +1 @@
|
|||||||
[{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Tracking']]/Effects/Item/Name/@value"},{"kind":2,"language":"xpath","value":"sum(//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[@ClipIndex=0]/preceding-sibling::CRTrackClip/@Length)"},{"kind":2,"language":"xpath","value":"//CROwneUnit/CRCUnitArr[@Name=\"아름다운 꽃 축제 (Happy Flower Festival)\"]/@Name"},{"kind":2,"language":"xpath","value":"//Layer[Name[@value='{layer}']]/Effects/Item[EffectData/{option}]/Name/@value | //Layer[Name[@value='{layer}']]/Effects/Item/EffectData/{option}/@value"},{"kind":2,"language":"xpath","value":"//Layer[Name[@value='{layer}']]/Effects/Item/Name/@value | //Layer[Name[@value='{layer}']]/Effects/Item/EffectData/{option}/@value\r\n"},{"kind":2,"language":"xpath","value":"//CRTransFilter[@ClipIndex=count(//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='이미지3.jpg']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='이미지3.jpg']/../preceding-sibling::CRClip)][1]/preceding-sibling::CRTrackClip)][@Type='2']/@*[name()='ID' or name()='Range' or name()='Type']"},{"kind":2,"language":"xpath","value":"//CROwneUnit[1]/CRCUnitArr/@*[name()='VID600' or name()='VID601']"},{"kind":2,"language":"xpath","value":"//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path"}]
|
[{"kind":2,"language":"xpath","value":"//Layer[Name[@value='Tracking']]/Effects/Item/Name/@value"},{"kind":2,"language":"xpath","value":"sum(//CRTrackList[@Name='텍스트' or @Name='비디오2']/CRTrackClip[@ClipIndex=0]/preceding-sibling::CRTrackClip/@Length)"},{"kind":2,"language":"xpath","value":"//CROwneUnit/CRCUnitArr[@Name=\"아름다운 꽃 축제 (Happy Flower Festival)\"]/@Name"},{"kind":2,"language":"xpath","value":"//Layer[Name[@value='{layer}']]/Effects/Item[EffectData/{option}]/Name/@value | //Layer[Name[@value='{layer}']]/Effects/Item/EffectData/{option}/@value"},{"kind":2,"language":"xpath","value":"//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex='3']/@Length"},{"kind":2,"language":"xpath","value":"//CRTransFilter[@ClipIndex=count(//CRTrackList[@Name='비디오1']/CRTrackClip[@ClipIndex=count(//CRClip[@Path='이미지3.jpg']/preceding-sibling::CRClip | //CRClip[@Type='11']/CRCUnitArr[@Path='이미지3.jpg']/../preceding-sibling::CRClip)][1]/preceding-sibling::CRTrackClip)][@Type='2']/@*[name()='ID' or name()='Range' or name()='Type']"},{"kind":2,"language":"xpath","value":"//CROwneUnit[1]/CRCUnitArr/@*[name()='VID600' or name()='VID601']"},{"kind":2,"language":"xpath","value":"//CRClipArr/CRClip[@Type='11']/CRCUnitArr/@Path | //CRClipArr/CRClip[not(@Type='11')]/@Path"}]
|
||||||
Binary file not shown.
Reference in New Issue
Block a user