Greasy Fork

Greasy Fork is available in English.

视频外挂悬浮可点复制翻译字幕,floating-plug-in-for-clickable-subtitle-copying

视频外挂悬浮可点复制翻译字幕,floating plug-in for clickable subtitle copying

当前为 2023-12-17 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         视频外挂悬浮可点复制翻译字幕,floating-plug-in-for-clickable-subtitle-copying
// @description  视频外挂悬浮可点复制翻译字幕,floating plug-in for clickable subtitle copying
// @grant        GM_log
// @require      https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js
// @require      https://cdn.bootcss.com/vConsole/3.3.0/vconsole.min.js
// @include      *
// @match        *://*/*
// @namespace    http://tampermonkey.net/
// @version      2023.12.17.09.26.23
// @icon         https://www.google.com/s2/favicons?sz=64&domain=greasyfork.org
// @author       You
// ==/UserScript==

(()=>{ "use strict";
// import "./styles.css";
// GM_log("Hello world! GM_log")
// Your code here...
// 报错油猴脚本使用jquery报错eslint:no-undef-‘$‘ is not defined
// eslint-disable-next-line no-unused-vars
/* globals jQuery, $, waitForKeyElements */
// 彩色打印
  const clog = content=>{ console.log(`%c${content}`,"background-color: #811f21; color: white;line-height:1.5rem; padding:0 0.5rem;") };
  // 全屏封装
  function goFullScreen(element){ clog("全屏视频");
    // var element = document.getElementById("fullscreenElement");
    element.requestFullscreen ? element.requestFullscreen() : element.mozRequestFullScreen ? element.mozRequestFullScreen() : element.webkitRequestFullscreen ? element.webkitRequestFullscreen() : element.msRequestFullscreen && element.msRequestFullscreen() }function exitFullScreen(){ clog("退出全屏视频");document.exitFullscreen ? document.exitFullscreen() : document.mozCancelFullScreen ? document.mozCancelFullScreen() : document.webkitExitFullscreen ? document.webkitExitFullscreen() : document.msExitFullscreen && document.msExitFullscreen() }function checkFullScreen(element){
    // var element = document.getElementById("fullscreenElement");
    if(document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement){ if(element === document.fullscreenElement || element === document.mozFullScreenElement || element === document.webkitFullscreenElement || element === document.msFullscreenElement){ console.log("元素处于全屏状态");return true }console.log("元素不处于全屏状态");return false }console.log("不处于全屏状态");return false }function autoFullScreen(el){
    // var el = document,
    //   cfs = el.cancelFullScreen || el.webkitCancelFullScreen || el.mozCancelFullScreen || el.exitFullScreen,
    //   wscript;
    // if (typeof cfs != "undefined" && cfs) {
    //   cfs.call(el);
    //   return;
    // }
    if(checkFullScreen(el)){ exitFullScreen();return }goFullScreen(el);if(typeof window.ActiveXObject != "undefined"){
      // eslint-disable-next-line no-undef
      const wscript = new ActiveXObject("WScript.Shell");wscript != null && wscript.SendKeys("{F11}") } }
  // 等待网页完成加载
  window.addEventListener("load",function(){
    // 加载完成后执行的代码
    clog("视频外挂西悬浮可点复制翻译字幕-floating-plug-in-for-clickable-subtitle-copying");
    // 允许全屏
    $("iframe").each(function(){ $(this).attr("allowfullscreen","true") });
    // 移动端控制台
    // new VConsole();
    // 视频外层
    const videoElement = $("video");
    // 视频父元素
    // const videoParentElement = videoElement.wrapAll('<div class="videoWrapper" style="position: relative;"/>');
    const videoParentElement = videoElement.parent();videoParentElement.addClass("videoWrapper");videoParentElement.css({ position: "relative" });
    // 隐藏字幕轨道
    videoElement.append("<style>video::cue{opacity: 0 !important}</style>");videoElement.attr("controls","true");videoElement.attr("playsInline","true");
    // 全屏开关元素
    const clickable_subtitle_switch_button = $("<button class='switchButton'>全屏</button>");
    // 全屏开关事件
    clickable_subtitle_switch_button.on("click",function(event){ event.stopPropagation();clog("全屏开关点击");autoFullScreen(document.querySelector(".videoWrapper")) });
    // 公共样式
    const commontCss = { "z-index": "2147483647",color: "#fff",position: "absolute" };
    // 开关公共样式
    const buttonCommontCss = { margin: "1vw",display: "block",padding: "0.5vw","border-radius": ".5vw","background-color": "#1118","font-size": "1.5vw",cursor: "pointer","user-select": "text","line-height": "2.5rem !important",color: "#fffb" };
    // 全屏开关样式
    clickable_subtitle_switch_button.css({ ...buttonCommontCss });
    // 字幕显示开关元素
    const clickable_subtitle_show_switch_button = $("<button class='switchButton'>显隐</button>");let isShow_subtitle = true;
    // 字幕显示开关样式
    clickable_subtitle_show_switch_button.css({ ...buttonCommontCss });
    // 网页外挂字幕元素
    const clickable_subtitle_wapper = $("<div class='floating_plug_in_for_clickable_subtitle_copying'></div>");
    // 字幕显示开关事件
    clickable_subtitle_show_switch_button.on("click",function(event){ event.stopPropagation();clog("字幕显示开关点击");isShow_subtitle = !isShow_subtitle;clickable_subtitle_wapper.css({ display: isShow_subtitle ? "block" : "none" }) });
    // 网页外挂字幕事件
    clickable_subtitle_wapper.click(function(event){ clog("字幕外层点击");
      // console.log(' :', [videoElement]);
      // 阻止冒泡
      event.stopPropagation() });clickable_subtitle_wapper.on("mousedown",e=>{ e.stopPropagation();console.log(" :",[videoElement]);videoElement?.[0].pause() });clickable_subtitle_wapper.on("touchstart",e=>{ e.stopPropagation();console.log(" :",[videoElement]);videoElement?.[0].pause() });clickable_subtitle_wapper.on("mouseup",e=>{ e.stopPropagation();if(window?.getSelection()?.toString()){ console.log(" :",[videoElement]);videoElement?.[0].pause();return }console.log(" :",[videoElement]);videoElement?.[0].play() });clickable_subtitle_wapper.on("touchend",e=>{ e.stopPropagation();if(window?.getSelection()?.toString()){ console.log(" :",[videoElement]);videoElement?.[0].pause();return }console.log(" :",[videoElement]);videoElement?.[0].play() });
    // 网页外挂字幕样式
    clickable_subtitle_wapper.css({ ...commontCss,border: "2px solid #aaa8",transform: "translateX(-50%)",display: "block","user-select": "text",width: "80vw",bottom: "0",left: "50%",padding: "3vw 3vw 10vh 3vw","background-color": "#1b2129ee","line-height": "4rem !important","font-size": " 3vw","text-align": " center",mask: "linear-gradient(180deg, black 0%, rgba(0, 0, 0, 1) 80%,rgba(0, 0, 0, 0.0) 95%)","border-radius": "3vw 3vw 0 0","box-shadow": "inset 0 0 2vw #666" });
    // 字幕轨道
    const subtitleTrack = $('<track  class="videoTrack" kind = "subtitles" default /> ');videoElement.prepend(subtitleTrack);
    // 缓存字幕数据
    /* document.querySelector('.videoTrak') */subtitleTrack.on("loadeddata",e=>{ clog("轨道数据缓存");console.log("数据 :",e) });
    // 网页外挂字幕文件
    const clickable_subtitle_input_file = $(`<div><input id='input' style='font-size: 2vw;' class='clickable_subtitle_input_file' type='file'  accept='.vtt'>  </input><label style='font-size: 2vw;' for='input'>上传字幕文件(.vtt)</label>  </div> `);clickable_subtitle_input_file.css({ "font-size": " 2vw","background-color": "#0004","order-radius": " 2vw !important",padding: "1vw 4vw",display: "flex","justify-content": "space-between","align-items": "center" });const clickable_subtitle_input_file_transer = $(`<a style='color:#fff;display:block;' href='https://converter.app/srt-to-vtt/result.php?lang=cn' target='转格式'>字幕文件转格式(.srt->.vtt)网站</a>`);clickable_subtitle_input_file.css({ "font-size": "2vw" });
    // 字幕读取近内存
    clickable_subtitle_input_file.on("change",e=>{ e.stopPropagation();const file = e.target.files[0];console.log("file :",file);
      // window?.localStorage?.setItem(`${window.location.href}`, JSON.stringify(lastPlaybackPosition?.current))
      if(!file)return;document.querySelector(".videoTrack").src = URL.createObjectURL(file);
      // subtitleTrack.attr('src', URL.createObjectURL(file))
      console.log("视频元素 :",[videoElement]) });
    // 时间纠正
    let addTime = 0;
    // 上次播放秒
    let preSecondInt = -1;
    // 上次字幕小标
    let preSubIndex = -1;
    // 字幕显示时机
    videoElement.on("timeupdate",e=>{ e.stopPropagation();const videoEle = e?.target;const currentTime = videoEle?.currentTime + addTime;
      // console.log('视频元素 :', e);
      // console.log('视频时间 :', currentTime);
      // console.log('字幕数组1 :', videoEle?.textTracks[0]?.cues?.[0]);
      // console.log('字幕数组 :', videoEle?.textTracks[0]?.cues);
      const cues = videoEle?.textTracks[0]?.cues;
      // console.log('preSecondInt !== parseInt(videoEle?.currentTime) :', preSecondInt !== parseInt(videoEle?.currentTime), preSecondInt , parseInt(videoEle?.currentTime));
      // 节流每秒执行
      if(videoEle?.textTracks[0]?.cues?.length && preSecondInt !== parseInt(videoEle?.currentTime))
      // clog('数组有长度');
        for(let i = 0;i < cues.length;i++){ const item = cues[i];
          // console.log('debugger :', item?.startTime, currentTime, item?.endTime);
          const right = item?.startTime <= currentTime && item?.endTime >= currentTime;
          // 不是同一字幕才执行
          if(right){ if(preSubIndex !== i){ clog("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");console.log("当前时间 :",item?.startTime,currentTime,item?.endTime);console.log("当前时间秒 :",preSecondInt,parseInt(videoEle?.currentTime));console.log("当前字幕下标 :",preSubIndex,i);const textSele = item?.text?.split(/\s+/)?.map(v=>`<i>${v}</i>`).join("");clickable_subtitle_wapper.html(`<p class="clickable_subtitle_middle" style="user-select:text;">${textSele}</p>`);
            // 使用事件委派监听子元素的点击事件
            $(".clickable_subtitle_middle").on("click","i",function(){ clog($(this).text() + "被点击了");const word = e?.target?.textContent.match(/\b[\w]+\b/);navigator?.clipboard?.writeText(word)?.then(()=>{ clog("复制成功 " + word) })?.catch(()=>{ clog("复制失败 " + word) });
              // 选择元素配合欧路词典
              const range = document?.createRange();range?.selectNode(this);window?.getSelection()?.addRange(range) });
            // 上次字幕下标
            preSubIndex = i }break } }
      // const currentSubtitle = videoEle?.textTracks[0]?.cues?.find((item) => {
      //   const right = item?.startTime <= currentTime && item?.endTime >= currentTime
      //   // debugger
      //   return right
      // })?.text
      // clickable_subtitle_wapper.html(`<p style="user-select:text;">${currentSubtitle}</p>`)
      // 上一次时间
      preSecondInt = parseInt(videoEle?.currentTime) });
    // 射手字幕网找字幕
    const clickable_subtitle_find_subtitle_webSite = $("<a class='clickable_subtitle_find_subtitle_webSite' href='https://assrt.net/' target='字幕网'>找字幕文件网1 </a>");const clickable_subtitle_find_subtitle_webSite2 = $("<a class='clickable_subtitle_find_subtitle_webSite' href='https://www.opensubtitles.org/zh' target='字幕网'>找字幕文件网2 </a>");const clickable_subtitle_find_subtitle_webSite3 = $("<a class='clickable_subtitle_find_subtitle_webSite' href='https://subscene.com/' target='字幕网'>找字幕文件网3 </a>");clickable_subtitle_find_subtitle_webSite.css({ color: "#fff" });clickable_subtitle_find_subtitle_webSite2.css({ color: "#fff" });clickable_subtitle_find_subtitle_webSite3.css({ color: "#fff" });
    // 找字幕外层
    const clickable_subtitle_find_subtitle_wapper = $("<div class='clickable_subtitle_find_subtitle_wapper'></div>");const clickable_subtitle_find_subtitle_webSite_wapper = $("<div class='clickable_subtitle_find_subtitle_webSite_wapper'></div>");clickable_subtitle_find_subtitle_webSite_wapper.css({ display: "flex","justify-content": "space-between","align-items": "center","font-size": "2vw","order-radius": "2vw !important",padding: "1vw 4vw","background-color": "#0004" });clickable_subtitle_find_subtitle_webSite_wapper.append(clickable_subtitle_find_subtitle_webSite);clickable_subtitle_find_subtitle_webSite_wapper.append(clickable_subtitle_find_subtitle_webSite2);clickable_subtitle_find_subtitle_webSite_wapper.append(clickable_subtitle_find_subtitle_webSite3);clickable_subtitle_find_subtitle_wapper.append(clickable_subtitle_input_file);clickable_subtitle_find_subtitle_wapper.append(clickable_subtitle_input_file_transer);clickable_subtitle_find_subtitle_wapper.append(clickable_subtitle_find_subtitle_webSite_wapper);clickable_subtitle_wapper.prepend(clickable_subtitle_find_subtitle_wapper);
    // 准备改成父级嵌套
    // 挂载开关
    const videoWrapper = $(".videoWrapper");videoWrapper.css({ "font-size": "2vw","line-height": "2.5rem !important",padding: "0 1rem !important" });
    // 按钮外框
    const buttonWrapper = $(`<div class="buttonWrapper"/>`);buttonWrapper.css({ ...commontCss,top: "50%",right: "0",color: "#fff",transform: "translateY(-50%)" });
    // /移动端点击视频出现按钮
    videoElement.on("touchstart",e=>{ e.stopPropagation();buttonWrapper.css({ opacity: "1",transition: "all 0.5s ease-in-out" }) });videoElement.on("touchend",e=>{ e.stopPropagation();this.setTimeout(()=>{ buttonWrapper.css({ opacity: "0.1",transition: "all 0.5s ease-in-out" }) },1e3) });
    // 有定时器标识变量
    // eslint-disable-next-line no-unused-vars
    let mouseStopped = true;
    // 电脑滑动鼠标出现那妞
    $(document).on("mousemove",function(e){ e.stopPropagation();
      // 设置鼠标停止移动的标识为false
      mouseStopped = false;
      // 清除延迟定时器
      clearTimeout($.data(this,"timer"));
      // 电脑滑动鼠标出现那妞
      buttonWrapper.css({ opacity: "1",transition: "all 0.5s ease-in-out" });
      // 电脑鼠标停止移动隐藏按钮
      // 设置新的延迟定时器
      $.data(this,"timer",setTimeout(()=>{ mouseStopped = true;buttonWrapper.css({ opacity: "0.1",transition: "all 0.5s ease-in-out" }) },1e3)) });
    // 字幕加一秒
    const add = $("<button>加</button>");add.css({ ...buttonCommontCss });
    // 偏移速度显示屏
    const speed = $("<div>0秒</div>");speed.css({ ...buttonCommontCss });
    // 改变速度
    const changeTime = ()=>{ speed.text(addTime + "秒") };add.on("click",e=>{ e.stopPropagation();addTime++;changeTime() });
    // 字幕减一秒
    const reduce = $("<button>减</button>");reduce.css({ ...buttonCommontCss });reduce.on("click",e=>{ e.stopPropagation();addTime--;changeTime() });
    // 字幕广告插入速度纠正
    const subTitleSpeedWaper = $("<div/>");subTitleSpeedWaper.css({ display: "flex","justify-content": "space-between","align-items": "center" });
    // buttonCommontCss
    buttonWrapper.append(clickable_subtitle_switch_button);buttonWrapper.append(clickable_subtitle_show_switch_button);buttonWrapper.append(reduce);buttonWrapper.append(speed);buttonWrapper.append(add);
    // buttonWrapper.append(subTitleSpeedWaper);
    // 挂载字幕元素
    videoWrapper.append(buttonWrapper);videoWrapper.append(clickable_subtitle_wapper);
    //全部元素可选
    $("*").css("user-select","text") },false) })();