☰

javlibrary enhancement

javlibrary网站 增强内容包括:预览视频、在线播放、下载链接、预览图补全 etc.

Terá de instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

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

Terá de instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão de gestão de scripts de utilizador para instalar este script.

(Já tenho um gestor de scripts de utilizador, deixe-me instalá-lo!)

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

(Já tenho um gestor de estilos de utilizador, deixe-me instalá-lo!)

// ==UserScript==
// @name         javlibrary enhancement
// @name:zh      javlibrary 图书馆网站增强
// @namespace    http://tampermonkey.net/
// @version      1.0.1
// @description  javlibrary网站 增强内容包括:预览视频、在线播放、下载链接、预览图补全 etc.
// @author       https://greasyfork.org/zh-CN/users/25283
// @match        https://*.javlibrary.com/*
// @icon         https://www.javlibrary.com/favicon.ico
// @grant        GM_xmlhttpRequest
// @connect      cc3001.dmm.co.jp
// @connect      pics.dmm.co.jp
// @connect      pics.dmm.com
// @connect      www.dmm.com
// @connect      www.dmm.co.jp
// @connect      sukebei.nyaa.si
// @connect      missav.ws
// @connect      av-wiki.net
// @connect      supjav.com
// @license      MIT
// ==/UserScript==
//在前人的基础上修改,增强内容包括:
//  1、首页热门影片预览图高度固定,在高分显示器上预览图太小了,放大画面的话就会显示不全,修改热门影片列表高度为自动。(建议在4K显示器放大画面设为175%或200%)
//  2、由于DMM反盗链,以前的视频地址失效了,更新了影片预览视频的方式,直接嵌入DMM的预览页面。需要注意,DMM的视频只允许日本IP预览,日本以外的IP会被拒绝。
//  3、添加VR影片的预览视频,无须VR眼镜也能观看,由于DMM的VR视频页禁止嵌入,只能做成链接形式,但好处是可以全屏放大,方法是按F11键,并且VR影片可以用鼠标拖动调整视角,提高观影体验。
//  4、如果图书馆的预览截图缺失,尝试重新补足 示例:REBD-669 和 ABF-226,切换插件开关可以看到效果。
//  5、如果你有下片时收藏封面图和预览图和预览视频的习惯,可以在浏览器扩展商店安装Chrono下载器插件,然后在预览图下方链接,右键可以批量保存预览图,省却你一张一张点的麻烦。
//  6、直接显示Sukebei.nyaa.si的搜索结果,在页内就可以直接下载影片。
//  7、将左侧导航栏和顶部Logo隐藏,并增加5项分类标签,方便直达特殊分类。
//本插件专注四项核心需求:预览视频、在线播放、下载链接、预览图补全,页面干净清爽,秒杀其他一堆乱七八糟功能搞得页面混乱不堪的脚本,请试着关闭其他脚本感受一下。
//尽量少修改页面元素,可以最大限度与其他脚本兼容。有疑问请站内私讯 Warma

(function () {
    'use strict';
const gmFetch = (url, { method, headers, anonymous } = {}) => new Promise((onload, onerror) => {GM_xmlhttpRequest({ url, method, headers, anonymous, onload, onerror })})
const parseHTML = (str) => {const tmp = document.implementation.createHTMLDocument();tmp.body.innerHTML = str; return tmp;}
//const check = async (src) => (await gmFetch(src, { method: 'HEAD' })).status === 200

function normalizeString(str) {
  if (typeof str !== 'string') return str;
  str.replace("55t38","55t3800") //T38-***系列的需要特殊处理
  // 惰性前缀 + 贪婪末尾数字(至少 3 位),一次性完成拆分
  const m = /^(.*?)(\d{3,})$/.exec(str);
  if (!m) return str; // 无法拆分,原样返回

  const prefix = m[1];
  const digits = m[2];
  const arr = [
    ['41hodv', '5642hodv'],
    ['9oae', 'oae'],
  ];

  const map = new Map(arr);

  const replacedFront = map.has(prefix) ? map.get(prefix) : prefix;

  // 只有恰好 3 位时才补两个 0
  let newDigits = digits.length === 3 ? '00' + digits : digits;

  // 总长度不足 5 位 → 前面补 0 至 5 位
  if (newDigits.length < 5) {
    newDigits = newDigits.padStart(5, '0');
  }
  return replacedFront + newDigits;
}

function mainpage(){ // 优化首页显示效果
console.log("首页");
try{
    var leftmenu = document.querySelector("#leftmenu");
    var rightcolumn = document.querySelector("#rightcolumn");
    // 左边导航菜单增加几项分类
    const node = document.querySelector("#leftmenu > div > ul > li:nth-child(3)");
    node.insertAdjacentHTML('afterend', '<li><a href="vl_genre.php?g=aazq" style="color:red">漫改作品</a></li>')
    node.insertAdjacentHTML('afterend', '<li><a href="vl_genre.php?g=anbq" style="color:red">高品质VR</a></li>')
    node.insertAdjacentHTML('afterend', '<li><a href="vl_genre.php?g=aaua" style="color:red">新发行VR</a></li>')
    node.insertAdjacentHTML('afterend', '<li><a href="vl_genre.php?g=a5gq" style="color:red">介绍影片</a></li>')
    node.insertAdjacentHTML('afterend', '<li><a href="vl_genre.php?g=my" style = "color:red">新人亮相</a></li>')

    leftmenu.style.display='none'; // 隐藏左侧导航栏
    document.querySelector("#toplogo").style.display='none'; // 隐藏LOGO
    rightcolumn.style.margin='0px 10px 10px 0px';
    var boxtitle = document.querySelector("#rightcolumn > div.boxtitle");
    if (!boxtitle) {const $position = document.querySelector("#video_title");
        const html = `<div class="boxtitle"><a onclick="leftmenu.style.display='inline-block';rightcolumn.style.margin='0px 10px 10px 180px';return false;"> &gt;&gt;&gt;<b style="color:red">显示</b>&lt;&lt;&lt; </a>左边导航菜单</div>`
        $position.insertAdjacentHTML('beforebegin', html);}
    else{boxtitle.innerHTML += '<a onclick="leftmenu.style.display=\'inline-block\';rightcolumn.style.margin=\'0px 10px 10px 180px\';return false;"> &gt;&gt;&gt;<b style="color:red">显示</b>&lt;&lt;&lt; </a>左边导航菜单';}
    var category = document.querySelector("#leftmenu > div > div.category");
    category.innerHTML += '<a onclick="leftmenu.style.display=\'none\';rightcolumn.style.margin=\'0px 10px 10px 0px\';return false;">   &gt;&gt;&gt;<b style="color:red">隐藏</b>&lt;&lt;&lt; </a>';

    document.querySelector("#rightcolumn > div.videothumblist").style.height = '100%'; // 首页热门影片高度自动调整
    document.querySelector("#leftmenu > div > ul:nth-child(2) > li:nth-child(2)").remove(); //18禁游戏
    document.body.insertAdjacentHTML('afterend', '<style>.videothumblist .videos .video{display:inline-flex !important;height:auto !important} .videothumblist .videos .video .title{height:auto !important} </style>')

    // 删除首页底部的一长串介绍文字
    var elements = document.getElementsByClassName("about");
    var array = Array.from(elements); array.forEach(function (element) {element.remove();}); //关于Javlibrary
    return;
}catch (error) {};
//try{}catch (error) {console.error("首页效果错误",error);};
}
mainpage()

try{ // 优化影片详情页显示效果
console.log("详情页");
    var video_jacket_img = document.querySelector("#video_jacket_img"); if (!video_jacket_img) return;
    var imgpath = video_jacket_img.src.replace("so/","/").split('/')[6]; var imgpath1 = imgpath.substr(0,1); var imgpath3 = imgpath.length>5 ? imgpath.substr(0,3):imgpath.substr(0,2)+"0"; //例子:BeFree系列 bf728
    var imgpathrest = imgpath.substr(0,imgpath.length-3); var imgpathnum = imgpath.substr(imgpath.length-3,3); var imgpath00 = imgpathrest+'00'+imgpathnum
    var avid = document.querySelector("head > meta[name=keywords]").content.split(", "); // 两种格式的番号:SONE-001,sone001 使用avid[0],avid[1]选择,未来扩展功能备用。
    const $stylesheet = document.querySelector("head > link[rel=stylesheet]")
    const html = '<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" type="text/css" rel="stylesheet">'
    $stylesheet.insertAdjacentHTML('afterend', html);
    document.querySelector("#video_id > table > tbody > tr > td.header").innerHTML += '<a href=\"https://123av.com/ja/search?keyword='+avid[0]+'\" title=\"搜索123AV\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    document.querySelector("#video_date > table > tbody > tr > td.header").innerHTML += '<a href=\"https://sukebei.nyaa.si/?q='+avid[0]+'\" title=\"搜索Sukebei\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    document.querySelector("#video_label > table > tbody > tr > td.header").innerHTML += '<a href=\"https://av-wiki.net/'+avid[0]+'/\" title=\"搜索AV-Wiki\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    document.querySelector("#video_maker > table > tbody > tr > td.header").innerHTML += '<a href=\"https://supjav.com/zh/?s='+avid[0]+'\" title=\"搜索SupJav\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    document.querySelector("#video_length > table > tbody > tr > td.header").innerHTML += '<a href=\"https://missav.ws/search/'+avid[0]+'\" title=\"搜索MissAV\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    document.querySelector("#video_director > table > tbody > tr > td.header").innerHTML += '<a href=\"https://www.javbus.com/'+avid[0]+'\" title=\"搜索JavBus\" target=\"sukebei\"><i class="fa fa-search"></i></a>'
    const $position = document.querySelector("#rightcolumn > hr");if (!$position) return;

function previewsection(){
    const race = (promises) => {
        console.log("测试预览视频");
        const newPromises = promises.map((p) => new Promise((resolve, reject) => p.then((v) => v && resolve(v), reject)));
        newPromises.push(Promise.all(promises).then(() => false));
        return Promise.race(newPromises)
    }

    const preview = async() => {
		const vpdm = async() => {var video1 = 'https://pics.dmm.co.jp/digital/video/'+imgpath+'/'+imgpath+'-1.jpg';
            try {
                const check = async (src) => (await gmFetch(src, { method: 'HEAD' })).status === 200
                if (await check(video1)) {return imgpath};} catch (error) {}
		}

        const vpdmm = async() => {var video2 = 'https://pics.dmm.co.jp/digital/video/'+imgpath00+'/'+imgpath00+'-1.jpg';
            try {
                const check = async (src) => (await gmFetch(src, { method: 'HEAD' })).status === 200
                if (await check(video2)) {return imgpath00};} catch (error) {}
        }

        let src = await race([vpdmm(), vpdm()])
        if (src){
        for (let i=1;i<=20;i++){ // 这里偷懒未做判断,直接显示20个预览图,所以有可能会有无效的预览图
                var thumbssrc ='https://pics.dmm.co.jp/digital/video/'+src+'/'+src+'jp-'+i+'.jpg'
                var thumbssrc2='https://pics.dmm.co.jp/digital/video/'+src+'/'+src+'-'+i+'.jpg'
                thumbsrc += '<a href="'+thumbssrc+'"><img width="120" height="90" border="0" src="'+thumbssrc2+'" ></a>';
            };
        try{document.querySelector("#rightcolumn > div.previewthumbs").remove();}catch (error) {}
        const html =`<div class="previewthumbs" style="display:block; margin:10px auto;"></div>`
        const $position = document.querySelector("#rightcolumn > div.socialmedia");
        $position.insertAdjacentHTML('afterend', html);
        document.querySelector("#rightcolumn > div.previewthumbs").innerHTML = thumbsrc;
        // 创建批量保存预览图的链接
        imgjacket_tag = document.querySelectorAll('#rightcolumn > div.previewthumbs > a');
        var imghref = 'https://pics.dmm.co.jp/digital/video/'+src+'/'+src+'jp-[1:20].jpg';
        const html1 =`<br> <a href=${imghref} onclick="return false;"> [右键用Chrono插件的菜单(链接另存为...)批量保存缩略图]</a> [预览补足] <a id='searchdmm' href='https://video.dmm.co.jp/av/list/?key=${normalizeString(avid[1])}' target=blank>  搜索DMM </a> `;
        $position.insertAdjacentHTML('beforebegin', html1);
        document.querySelector("#rightcolumn > div.socialmedia").remove(); // 删除社交网站图标栏
            preview2();
        }
    }

    const preview2 = async() => {
        var imgpath22 = document.querySelector("#rightcolumn > div.previewthumbs > a").href.split("/")[5]
        imgpath22 = normalizeString(imgpath22)
        var avid = document.querySelector("head > meta[name=keywords]").content.split(", ");
        if (avid[0].indexOf("VR") !== -1) {
            const $position = document.querySelector("#searchdmm")
            const html = `<a href="https://www.dmm.co.jp/digital/-/vr-sample-player/=/cid=${imgpath22}/" target=_blank >  点击打开VR预览视频(VR预览视频可以用鼠标拖动切换视角) </a>`;
            $position.insertAdjacentHTML('afterend', html)
        } else {
            var src = 'https://www.dmm.co.jp/service/digitalapi/-/html5_player/=/cid='+imgpath22+'/';
        }
console.log(src);
        if (src) document.querySelector("#video_webplayer").style.display = 'block';
            document.querySelector("#WebPlayer").src = src;
    }

    try{ //预览补足
        console.log("预览补足");
        var imgjacket_tag = document.querySelectorAll('#rightcolumn > div.previewthumbs > a ');
        if (imgjacket_tag.length == 0) { // 如果预览图缺失,尝试补足 示例:REBD-937 和 ABF-226
            var thumbsrc = '';
            var thumbsrc00 = 'https://pics.dmm.co.jp/digital/video/'+imgpath00+'/'+imgpath00+'jp-1.jpg';
//          var thumbsrc00 = 'https://pics.dmm.co.jp/digital/video/h_346rebd00937/h_346rebd00937jp-1.jpg' 例子
//          var thumbsrc00 = 'https://pics.dmm.co.jp/digital/video/118abf226/118abf226jp-1.jpg' 例子
            preview();

        }//待扩展
        else { // 创建批量保存预览图的链接
            var imghref = imgjacket_tag[imgjacket_tag.length-1].getAttribute('href'); imghref = imghref.replace('jp-','jp-[1:'); imghref = imghref.replace('.jpg','].jpg');
            const html =`<br> <a href=${imghref} onclick="return false;"> [右键用Chrono插件的菜单(链接另存为...)批量保存缩略图]</a> <a id='searchdmm' href='https://video.dmm.co.jp/av/list/?key=${normalizeString(avid[1])}' target=blank>  搜索DMM </a>`;
            $position.insertAdjacentHTML('beforebegin', html);
            document.querySelector("#rightcolumn > div.socialmedia").remove(); // 删除社交网站图标栏
        }

        try { // 尝试获取预览视频,使用iframe
            const html = '<div id="video_webplayer" style="display:none;"><iframe src="" width="640" height="360" target="_self" scrolling="no" allow="autoplay; fullscreen;" style="border:0;" id="WebPlayer" name="WebPlayer"></iframe></div>'
            $position.insertAdjacentHTML('afterend', html);
        } catch (error) {console.error("预览视频错误");}

        preview2()

    }catch (error) {console.error("预览补足错误");}
}
previewsection()

function commentsection(){
//将评论里面只有推广链接没有评论内容的评论删掉
    console.log("评论");
    try{var elements = document.querySelectorAll("#video_comments > table > tbody > tr > td.t > div > b > a");
       var array = Array.from(elements); array.forEach(function (element) {element.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.remove();}); //使用者文章的种子链接
    }catch {};
    try{elements = document.querySelectorAll("#video_comments > table > tbody > tr > td.t > div > a");
       array = Array.from(elements); array.forEach(function (element) {element.parentNode.parentNode.parentNode.parentNode.parentNode.remove();}); //使用者文章的种子链接
    }catch {};
}
commentsection()

async function sukibeilinks() {
console.log("Sukibei")
try{ // 显示Sukebei的搜索结果磁力链
  const $position = document.querySelector("#videoimages");
  const res = await gmFetch(`https://sukebei.nyaa.si/?q=${avid[0]}`, {method: 'GET', anonymous: true, headers: {'Accept':'text/html,application/xhtml+xml,application/xml', 'User-Agent': 'Android'},});
  const sukebei = parseHTML(res.responseText).querySelector("body > div > div > table");
  if (sukebei){
  var tds = sukebei.querySelectorAll("body > div > div > table > tbody > tr > td:nth-child(1)")
  var array = Array.from(tds);
  array.forEach(element => {element.remove();});
  sukebei.querySelector("body > div > div > table > thead > tr > th").remove()
  tds = sukebei.querySelectorAll("body > div > div > table > tbody > tr > td:nth-child(1) > a")
  array = Array.from(tds);
  array.forEach(element => {
      element.removeAttribute("href");
      element.innerHTML = element.innerHTML.toString().replace("中文","<b style='color:red;'>中文</b>");
      element.innerHTML = element.innerHTML.toString().replace("FHDC","FHDC<b style='color:red;'>中文字幕</b>");
  });
  tds = sukebei.querySelectorAll("body > div > div > table > tbody > tr > td:nth-child(2)")
  array = Array.from(tds);
  array.forEach(element => {element.innerHTML = element.innerHTML.toString().replace('/download', 'https://sukebei.nyaa.si/download');});
  $position.insertAdjacentHTML('beforebegin', "<table border='1'>"+sukebei.innerHTML+'</table><br>');
  }
}catch (error) {console.error("Sukebei搜索结果错误");}
}
sukibeilinks()

const SupJav = async() => {
console.log("SupJav");
    try {
        const response = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method:'GET', url:"https://supjav.com/zh/?s="+avid[0], onload:resolve, onerror:reject});});
        const SupLink = parseHTML(response.responseText).querySelector("div.post > a")
        const Suphtml = "<br><a href='"+SupLink.href+"' target=\"sukebei\">Supa "+SupLink.title+"</a>"
        const $position = document.querySelector("#owned")
        $position.insertAdjacentHTML('afterend', Suphtml)
    }catch (error) {console.error("SupJav错误");}
}
SupJav()

}catch (error) {}

function MissAV() { // 获取MissAV的链接,如果显示多条,可能是有无码和/或中文。
    async function checkVideoAvailability(avid) {
        try {
            const response = await new Promise((resolve, reject) => {GM_xmlhttpRequest({method:'GET', url:"https://missav.ws/search/"+avid, onload:resolve, onerror:reject});});

            if (response.status !== 200) throw new Error(`HTTP错误: ${response.status}`);

                 const MissLink = parseHTML(response.responseText).querySelectorAll("body > div:nth-child(47) > div.sm\\:container.mx-auto.px-4.content-with-search.pb-12 > div.grid.grid-cols-2.md\\:grid-cols-3.xl\\:grid-cols-4.gap-5 > div > div > div > a.text-secondary.group-hover\\:text-primary")
                 MissLink.forEach(element => {
                 const MissHtml = "<br><a href='"+element.href+"' target=\"sukebei\">Miss "+element.text+"</a>"
                 const $position = document.querySelector("#owned")
                 $position.insertAdjacentHTML('afterend', MissHtml)
             })
        } catch (error) {}
    }

    function displayMissAVLink() {
        const avid = document.querySelector("head > meta[name=keywords]").content.split(",")[0]
        checkVideoAvailability(avid);
    }

    displayMissAVLink();
}

MissAV();
})();