152 lines
3.9 KiB
JavaScript
152 lines
3.9 KiB
JavaScript
const SRT_ID = 'srtFile';
|
|
const VIDEO_ID = 'videoFile';
|
|
|
|
const srtInput = document.querySelector('#srtFile');
|
|
const videoInput = document.querySelector('#videoFile');
|
|
const video = document.querySelector('#video');
|
|
const textArea = document.querySelector('#textArea');
|
|
const status = document.querySelector('#status');
|
|
const reactTime = 0.4;
|
|
let subTexts = [];
|
|
let currentStamping = 0;
|
|
let lines = [];
|
|
|
|
function clamp(num) {
|
|
return Math.max(num, 0);
|
|
}
|
|
|
|
const keyMap = {
|
|
'k': video => {
|
|
if (currentStamping >= lines.length) {
|
|
return;
|
|
}
|
|
|
|
lines[currentStamping + 1][0] = clamp(video.currentTime - reactTime);
|
|
if (lines[currentStamping][1] > video.currentTime - reactTime || lines[currentStamping][1] === null){
|
|
lines[currentStamping][1] = clamp(video.currentTime - 0.03 - reactTime);
|
|
}
|
|
|
|
currentStamping += 1;
|
|
},
|
|
'l': video => {
|
|
lines[currentStamping] = [
|
|
lines[currentStamping][0],
|
|
video.currentTime - reactTime
|
|
];
|
|
},
|
|
'i': () => {
|
|
currentStamping -= 1;
|
|
},
|
|
'o': () => {
|
|
currentStamping += 1;
|
|
},
|
|
'u': () => (video.currentTime -= 2),
|
|
'p': () => (video.currentTime += 2),
|
|
'q': () => makeSRT()
|
|
};
|
|
|
|
function getCurrentStatus() {
|
|
return `Stamping Line ${currentStamping} | Playhead: ${video.currentTime}`;
|
|
}
|
|
|
|
function execHotkey(keyMap) {
|
|
document.addEventListener('keypress', function(e) {
|
|
const execFn = keyMap[e.key.toLowerCase()];
|
|
if (typeof execFn === 'function') {
|
|
execFn(video);
|
|
updateContent();
|
|
}
|
|
});
|
|
}
|
|
|
|
function updateContent() {
|
|
const head = '** 目前 ---> ';
|
|
|
|
const content = subTexts
|
|
.slice(currentStamping, currentStamping + 5)
|
|
.map((text, i) => {
|
|
const [timeStart, timeEnd] = lines[currentStamping + i];
|
|
return `${i === 0 ? head : ''}${text} | ${timeStart} --> ${timeEnd}`;
|
|
})
|
|
.join('\n');
|
|
|
|
textArea.value = content;
|
|
}
|
|
|
|
function handleFileUpload(e) {
|
|
if (e.target.files !== null) {
|
|
const reader = new FileReader();
|
|
const file = e.target.files[0];
|
|
|
|
/*
|
|
if it's srt file, fill text area with srt content
|
|
if it's video, load it into video tag
|
|
*/
|
|
reader.onload = function() {
|
|
if (e.target.id === SRT_ID) {
|
|
subTexts = reader.result.split('\n');
|
|
subTexts.forEach((_, i) => (lines[i] = [null, null]));
|
|
lines[0][0] = 0;
|
|
|
|
updateContent();
|
|
|
|
execHotkey(keyMap);
|
|
}
|
|
};
|
|
|
|
reader.onerror = function() {
|
|
alert('無法讀取檔案!');
|
|
};
|
|
|
|
if (e.target.id === SRT_ID) {
|
|
reader.readAsText(file);
|
|
} else {
|
|
video.src = URL.createObjectURL(file);
|
|
}
|
|
}
|
|
}
|
|
|
|
videoInput.addEventListener('change', handleFileUpload);
|
|
srtInput.addEventListener('change', handleFileUpload);
|
|
|
|
video.addEventListener('timeupdate', function(e) {
|
|
status.textContent = getCurrentStatus();
|
|
});
|
|
|
|
function makeSRT() {
|
|
srt = '';
|
|
for (let i = 0; i < subTexts.length; i++) {
|
|
// line number
|
|
srt += i + 1 + '\n';
|
|
// line time
|
|
let sh, sm, ss, sms;
|
|
let eh, em, es, ems;
|
|
const [timeStart, timeEnd] = lines[i];
|
|
const leftPad = str => `${str}`.padStart(2, '0');
|
|
const leftPad3 = str => `${str}`.padStart(3, '0');
|
|
sh = leftPad(Math.floor(timeStart / 3600));
|
|
sm = leftPad(Math.floor((timeStart % 3600) / 60));
|
|
ss = leftPad(Math.floor(timeStart % 60));
|
|
sms = leftPad3(Math.floor((timeStart * 1000) % 1000));
|
|
eh = leftPad(Math.floor(timeEnd / 3600));
|
|
em = leftPad(Math.floor((timeEnd % 3600) / 60));
|
|
es = leftPad(Math.floor(timeEnd % 60));
|
|
ems = leftPad3(Math.floor((timeEnd * 1000) % 1000));
|
|
|
|
srt += `${sh}:${sm}:${ss},${sms} --> ${eh}:${em}:${es},${ems}\n`;
|
|
srt += subTexts[i];
|
|
srt += '\n\n';
|
|
}
|
|
console.log(srt);
|
|
let blob = new Blob([srt], {
|
|
type: 'text/plain;charset=utf-8'
|
|
});
|
|
const a = document.createElement('a');
|
|
const file = new Blob([srt], { type: 'text/plain;charset=utf-8' });
|
|
a.href = URL.createObjectURL(file);
|
|
a.download = 'srt.txt';
|
|
a.click();
|
|
URL.revokeObjectURL(a.href);
|
|
a.remove();
|
|
}
|