您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Watch DMM video with subtitles. Drag srt file to the player.
// ==UserScript== // @name DMM Subtitle // @name:zh-TW DMM 外掛字幕 // @author ug945 // @description Watch DMM video with subtitles. Drag srt file to the player. // @description:zh-TW DMM 外掛字幕。拖曳字幕檔進播放器即可。 // @version 0.1.3 // @match https://www.dmm.co.jp/digital/-/player/=/player=html5/* // @grant none // @run-at document-idle // @namespace https://greasyfork.org/users/466290 // ==/UserScript== var style = document.createElement('style'); style.innerHTML = ` .area-subControls { float: left; margin-top: -30px; } .area-subControls > div { float: right; } .btn-sub { cursor: pointer; width: 50px; line-height: 27px; margin-top: -2px; color: #939393; font-size: 11px; text-align: center; } .area-sub { position: relative; margin: 0 12px 0 12px; } `; document.body.appendChild(style); var videoPlayer = document.querySelector("video"); var videoTrack = document.createElement('track'); videoTrack.kind = "subtitles"; videoTrack.setAttribute("default", ""); videoPlayer.appendChild(videoTrack); var divSubOffset = document.createElement('div'); divSubOffset.classList.add("area-sub"); divSubOffset.id = "sub_offset"; divSubOffset.innerHTML = "+0ms"; divSubOffset.offset = 0; divSubOffset.lock = false; var buttonSubMinus = document.createElement('div'); buttonSubMinus.classList.add("area-sub"); buttonSubMinus.classList.add("button"); buttonSubMinus.id = "sub_minus100"; buttonSubMinus.innerHTML = `<div class="btn-sub is-active active-mode">-200ms</div>`; var buttonSubPlus = document.createElement('div'); buttonSubPlus.classList.add("area-sub"); buttonSubPlus.classList.add("button"); buttonSubPlus.id = "sub_plus100"; buttonSubPlus.innerHTML = `<div class="btn-sub is-active active-mode">+200ms</div>`; buttonSubMinus.addEventListener('click', onSubMinusClicked, false); buttonSubPlus.addEventListener('click', onSubPlusClicked, false); var subControls = document.createElement('div'); subControls.classList.add("area-subControls"); subControls.classList.add("group"); subControls.style.display = "none"; document.getElementById("seek-padding").parentNode.appendChild(subControls); subControls.appendChild(divSubOffset); subControls.appendChild(buttonSubPlus); subControls.appendChild(buttonSubMinus); videoPlayer.addEventListener('dragover', handleDragOver, false); videoPlayer.addEventListener('drop', handleFileSelect, false); function onSubMinusClicked(event) { if(!divSubOffset.lock){ divSubOffset.lock = true; if(videoTrack.track.cues.length>0){ Array.from(videoTrack.track.cues).forEach((cue) => { cue.startTime -= 0.2; cue.endTime -= 0.2; }); divSubOffset.offset -= 200; divSubOffset.innerHTML = (divSubOffset.offset<0?"":"+") + divSubOffset.offset + "ms"; } divSubOffset.lock = false; } } function onSubPlusClicked(event) { if(!divSubOffset.lock){ divSubOffset.lock = true; if(videoTrack.track.cues.length>0){ Array.from(videoTrack.track.cues).forEach((cue) => { cue.startTime += 0.2; cue.endTime += 0.2; }); divSubOffset.offset += 200; divSubOffset.innerHTML = (divSubOffset.offset<0?"":"+") + divSubOffset.offset + "ms"; } divSubOffset.lock = false; } } function setTrack(file) { var reader = new FileReader(); reader.onload = function(evt) { var vtt = srt2webvtt(evt.target.result); var trackBlob = new Blob([vtt], {type:"text/plain;charset=utf-8"}); var trackUrl = URL.createObjectURL(trackBlob); videoTrack.src = trackUrl; divSubOffset.offset = 0; divSubOffset.innerHTML = (divSubOffset.offset<0?"":"+") + divSubOffset.offset + "ms"; subControls.style.display = "block"; }; reader.readAsText(file); } function handleFileSelect(evt) { evt.stopPropagation(); evt.preventDefault(); var files = evt.dataTransfer.files; var output = []; for (var i = 0, f; f = files[i]; i++) { setTrack(f) } } function handleDragOver(evt) { evt.stopPropagation(); evt.preventDefault(); evt.dataTransfer.dropEffect = 'copy'; } function srt2webvtt(data) { var srt = data.replace(/\r+/g, ''); srt = srt.replace(/^\s+|\s+$/g, ''); var cuelist = srt.split('\n\n'); var result = ""; if (cuelist.length > 0) { result += "WEBVTT\n\n"; for (var i = 0; i < cuelist.length; i=i+1) { result += convertSrtCue(cuelist[i]); } } return result; } function convertSrtCue(caption) { // remove all html tags for security reasons //srt = srt.replace(/<[a-zA-Z\/][^>]*>/g, ''); var cue = ""; var s = caption.split(/\n/); while (s.length > 3) { for (var i = 3; i < s.length; i++) { s[2] += "\n" + s[i] } s.splice(3, s.length - 3); } var line = 0; if (!s[0].match(/\d+:\d+:\d+/) && s[1].match(/\d+:\d+:\d+/)) { cue += s[0].match(/\w+/) + "\n"; line += 1; } if (s[line].match(/\d+:\d+:\d+/)) { var m = s[1].match(/(\d+):(\d+):(\d+)(?:,(\d+))?\s*--?>\s*(\d+):(\d+):(\d+)(?:,(\d+))?/); if (m) { cue += m[1]+":"+m[2]+":"+m[3]+"."+m[4]+" --> " +m[5]+":"+m[6]+":"+m[7]+"."+m[8]+"\n"; line += 1; } else { return ""; } } else { return ""; } if (s[line]) { cue += s[line] + "\n\n"; } return cue; }