Japonx 字幕&视频 下载【暂停更新】

下载 japonx 的字幕和视频。

// ==UserScript==
// @name        Japonx 字幕&视频 下载【暂停更新】
// @description 下载 japonx 的字幕和视频。
// @version     4.5.16.1
// @author      ThisAV
// @homepage    https://greasyfork.org/zh-CN/users/122964
// @namespace   https://greasyfork.org/users/122964
// @feedback    https://greasyfork.org/en/scripts/372676/feedback
// @connect     japronx.com
// @connect     japonx.net
// @connect     japonx.vip
// @connect     japonx.tv
// @connect     japonx.me
// @connect     1zb27xawwzcypdthone.com
// @include     /https?://([^.]+\.)?japonx.(net|vip|tv|me)/portal/index/detail/id//
// @include     /https?://([^.]+\.)?japonx.(net|vip|tv|me)/portal/index/detail/identification//
// @include     http://cdn.1zb27xawwzcypdthone.com/portal/index/detail/id/*
// @run-at      document-idle
// @require     https://cdn.staticfile.org/jquery/3.3.1/jquery.min.js
// @require     https://greasyfork.org/scripts/373130/code/ProtocolCheck.js?version=635816
// @icon        https://www.japonx.tv/favicon.ico
// @grant       GM_addStyle
// @grant       unsafeWindow
// @grant       GM_setClipboard
// @grant       GM_xmlhttpRequest
// @grant       GM_openInTab
// @grant       GM_notification
// ==/UserScript==

(function(){
    'use strict';
    var u=unsafeWindow,
        urls=location.href,
        host=location.hostname,
        PageId=location.href.replace(/.+\/identification\/(\w+).html/i,'$1'),
        VideoID=$('dt:contains(番號)').next().text().trim(), //番号
        VttLanguage=$('dt:contains(字幕)').next().text().trim(),//字幕语言类型
        AvIdol=$('dt:contains(女優)').next().text().trim(),//获得女优名字
        _VideoID=VttLanguage=='無'?'【无字幕】'+VideoID:VideoID,
        VideoUrl,
        VideoDownload=false,
        VideoSubUrl, PlayServer='p2',
        HidePic="http://p1.img.cctvpic.com/photoAlbum/templet/special/PAGE9dhkRStLqPhmlDLwNw6D180702/ELMTKZGgi45inXjtvdDG1eNV180705_1531386463.png", //隐藏图片时替代的图片
        webTitle=document.title=(VttLanguage=='無'?'【无字幕】':'')+VideoID+'【'+AvIdol+'】'+document.title,
        $btnDiv = $('#d-btn'),
        $M3U8Btn = $('<a class="d-btn">').css({'color':'blue','width':'100px','font-weight':'bold'}).attr({'id':'m3u8'}).text('获取中'),
        $zmBtn = $('<a class="btnC zm" style="color:#ccc;" href="javascript:void(0);">无字幕文件</a>').text('获取中'),
        $PotBtn = $('<a class="btnC PotPlayer">').css({'color':'black'}).text('Potplayer'),
        $ImgBtn = $('<a class="btnC HideImg">').text('IMG'),
        newM3U8Fn,
        M3U8TimeOut,
        M3U8_Expires, VttData/*字幕上传日期*/, VttHash/*字幕文件 Hash*/ //CheckVTT用,记录ajax中的信息;
    $btnDiv.append($M3U8Btn, $zmBtn, $PotBtn, $ImgBtn);
    GM_addStyle('#JaPonxTool{position:absolute;right:280px;top:20px;} .btnC{cursor:pointer;height:42px;font-size:18px;border:1px solid #d7dadb;padding:8px;margin-left:5px;border-radius:6px;display:inline-block!important;color:#000;background:#fff;}');

    var fanhao=['DANDY','VOSS','FERA','FSET','FUGA','HAWA','HBAD','IDOL','NHDTB','SDAM','SDDE','SDJS','SDMM','SVDVD','SW','MIZD','MIRD','MIFD','MIAA','MEYD'], fan, hao,
        fanhaoJSON={};
    for(var i=0;i<fanhao.length;i++) fanhaoJSON[fanhao[i]]=fanhao[i];

    var JaPronX={
        CheckUrl : function(url, callback, onerror){
            GM_xmlhttpRequest({
                url:url,
                headers: {
                    //'user-agent':'PotPlayer',
                    'Host':'japronx.com',
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                method:'head',
                synchronous:false,
                ontimeout:60000,
                onload: callback,
                onerror:onerror||function(e){
                    console.log('CheckUrl error:', e.status, url, e);
                    if(e.status==0) {
                        callback(e);
                        //$M3U8Btn.attr({'href':url,'target':'blank'}).text('服务器无响应,请求失败').css({'width':'250px','color':'red'});
                        //$M3U8Btn.attr({'href':url,'target':'blank'}).text('M3U8').css({'width':'250px','color':'red'});
                        //JaPronX.CheckTime();
                    }
                }
            });
        },
        CheckVTT : function(){
            if(VttLanguage=='無') {
                u.layer.tips('当前视频无字幕', $('dt:contains(字幕)').next().find('a'),{
                    tips: ['2', '#ff0000'],
                    tipsMore: true,
                    time: 0
                });
            }
        },
        HideImg : function(ctrl){
            var logo=HidePic, t;

            if(ctrl) {
                $('img[src*="/upload/admin/"]').each(function(){
                    var obj=this;
                    $(this).attr({'data-src':this.src,'src':logo}).bind({
                        mouseenter:function(){
                            t=setTimeout(function(e){obj.src=$(obj).data('src');}, 2000);
                        },
                        mouseleave:function(){
                            clearTimeout(t);
                            this.src=logo;
                        }
                    });
                });
            } else {
                $('img[src*="'+logo+'"]').each(function(){
                    $(this).off('mouseenter').unbind('mouseleave');
                    this.src=$(this).data('src');
                });
            }
        },
        newM3U8 : function(option, callback){
            u.layer.tips('点击刷新 M3U8 地址', '#m3u8', {tips:4, time: 10000});
            $M3U8Btn.attr({'href':'javascript:void(0)'}).bind('click', newM3U8Fn = function(){
                if(option)
                    if(callback) callback(0);
                clearTimeout(M3U8TimeOut);
                u.layer.msg('正在刷新 M3U8 地址');
                console.log(newM3U8Fn);
                ajaxGetID();
                newM3U8Fn = null;
            });
        },
        msgM3U8 : function(){
            var m3u8Url=this.href;
            if(this.href.indexOf('.m3u8')>-1) {
                GM_setClipboard(this.href);
                u.layer.msg('', {
                    content:'已复制 <a href="'+m3u8Url+'" download="'+_VideoID+'" color="blue">'+_VideoID+'</a> 地址<br><input type="checkbox" id="mp4"><label for="mp4">番号名+“.mp4”',
                    time: 0 //不自动关闭
                    ,btn: ['复制番号','刷新 M3U8', '关闭']
                    ,yes: function(index){
                        u.layer.close(index);
                        if($('#mp4').is(':checked')) _VideoID+=".mp4";
                        GM_setClipboard(_VideoID);
                        u.layer.msg('已复制番号');
                    },
                    btn2: function(index){
                        u.layer.close(index);
                        u.layer.msg('正在刷新 M3U8 地址');
                        $M3U8Btn.unbind('click', newM3U8Fn);
                        ajaxGetID();
                    }
                });
            }
            return false;
        },
        CheckTime : function(){
            u.layer.tips('点击刷新 M3U8 地址', '#m3u8', {tips:4, tipsMore: true,time: 60000});
            var CheckTime=300, CheckNewM3U8,
                t=setInterval(function(){
                    $M3U8Btn.text((CheckTime--)+'秒后自动重试');
                    if(CheckTime==0) {
                        clearInterval(t);
                        ajaxGetID();
                    }
                },1000);
            $M3U8Btn.css({'width':'230px'});
            JaPronX.newM3U8(true, function(e){
                CheckTime=e;
                clearInterval(t);
                return false;//中断后续的代码执行
            });
        }
    }

    if($('.system-message').length>0) {
        u.history.back=function(){return null;}
        var layer={
            tips:function(){return null;},
            open:function(){return null;},
            msg:function(){return null;}
        };
        $('.system-message>h1').text(':)');
        $('.jump').remove();
        PlayServer='svip';

        $btnDiv=$('.system-message').append($M3U8Btn.addClass('btnC'), $zmBtn.addClass('btnC'));
        if(1) $btnDiv.append($('<a class="d-btn sub" target="_blank" href="https://'+host+'/portal/index/ajax_get_js.html?identification='+PageId+'">Ajax</a>').addClass('btnC'));
    } else {

        $(document).scrollTop($('#contents-inline').offset().top);

        $('.d-btn.download').hide();//隐藏下载按钮
        if(0) $btnDiv.append('<a class="d-btn sub" target="_blank" href="https://'+host+'/portal/index/ajax_get_js.html?identification='+PageId+'">Ajax</a>');
        //恢复播放按钮
        if($('[id^="do_play_"]').length==0) {
            $('<a href="javascript:;" class="d-btn play" id="do_play_3">播放</a>').click(function(){
                u.player = true;
                ajax_get_js();
            }).insertBefore($M3U8Btn);
            $('<img id="do_play_2" style="width: 120px;height: 120px;left: 40%;top:35%;cursor: pointer;" class="btn_play" src="/themes/simpleboot3/public/assets2/img/btn_play.png">').click(function(){
                u.player = true;
                ajax_get_js();
            }).replaceAll('#video>:nth-child(1)');
        }



        var HideText=$('#wrap-slider, .wrap-header, #wrap-footer-bottom, .js-ajax-delete, h1, h2, .tx-comment, #works, .desc>:not(#d-btn)');  //干净模式
        $ImgBtn.dblclick(function(){
            if(!localStorage['HideText']) {
                localStorage['HideText']=true;
                u.layer.tips('已开启干净模式', '.HideImg');
                HideText.hide();
            } else {
                u.layer.tips('已关闭干净模式', '.HideImg');
                delete localStorage['HideText'];
                HideText.show();
            }
        }).click(function(){
            if(!localStorage['HideImg']) {
                u.layer.tips('已开启图片隐藏', '.HideImg');
                localStorage['HideImg']=true;
                JaPronX.HideImg(true);
            } else {
                u.layer.tips('已关闭图片隐藏', '.HideImg');
                delete localStorage['HideImg'];
                JaPronX.HideImg(false);
            }
        });
        if(localStorage['HideText']) HideText.hide();
        if(localStorage['HideImg']) JaPronX.HideImg(true);

        $('.desc>dt:contains(番號)').click(function(){
            GM_openInTab('http://www.javlib.com/cn/vl_searchbyid.php?keyword='+$(this).next().text(),'active')
        });

        $('.desc>dt:contains(番號)').next().click(function(){
            GM_setClipboard(_VideoID);
            u.layer.msg('已复制番号');
        });

    }
    var ajaxGetID=function(){
        GM_xmlhttpRequest({
            url : '/portal/index/ajax_get_js.html?identification='+PageId,
            method :'get',
            headers : {
                //'user-agent':'PotPlayer',
                'Host':'japronx.com',
                'Content-Type': 'application/x-www-form-urlencoded'
            },
            responseType : 'text',
            async : true,
            timeout : 60000,
            onload : function(e){
                $M3U8Btn.unbind('click');
                $M3U8Btn.unbind('click', newM3U8Fn);
                $M3U8Btn.bind('click',JaPronX.msgM3U8);
                var s=e.responseText;
                GM_addStyle("dl.desc {width:400px;} #d-btn{width:300px;} #contents-inline dl a:hover{border:1px solid #00aaff;margin:1px!important;} /*.play{margin-right:0px!important;}*/");
                //console.log('GM_xmlhttpRequest: ',e , s);
                //console.log('VideoUrl: ',VideoUrl);

                var Arry=s.split(/\||'\.split\('/i), M3U8_MD5, M3U8_Hash=[];
                console.log(fanhaoJSON);
                $.each(Arry,function(index,val){
                    //console.log(index, val.length, val);
                    //console.log(val, VideoID, "fan:", fan, fanhaoJSON[val]);
                    if(!VideoID&&!fan) {
                        if(fanhaoJSON[val]) fan=fanhaoJSON[val];
                        else {
                            if(val.length>=2&&val.length<=6) {
                                if(/^[A-Z]+/.test(val)&&!/false|color|png|hls|new|var|url|https|com|type|video|true|auto|hotkey|volume|lang|new|var|theme|svip|FADFA3/.test(val)) {
                                    fan=val;
                                }
                            }
                        }
                    }
                    switch(val.length) {
                            //M3U8 32位 Hash 提取
                        case 32: M3U8_Hash.push(val);break;
                        case 22: M3U8_MD5=val;break;
                        case 10: if(/\d{10}/.test(val)) M3U8_Expires=val;break;
                        case 8: if(/2\d{7}/.test(val)) VttData=val;break;
                            //检查是否为番号
                        case 5:
                        case 4:
                        case 3:if(!VideoID&&/^(\d{2,4}_?[CB]|\d{2,4}_?HD)?$/i.test(val)) hao=val.replace(/C$/i,'');
                    }
                });

                if(!VideoID) {
                    VideoID=fan+'-'+hao;
                    $('.error').append(':',(fanhaoJSON[fan]?fan:'<span style="color:red">'+fan+'</span>'),'-',hao);
                    document.title=VideoID;
                }

                //console.log(M3U8_Hash, M3U8_Hash.length, M3U8_MD5, M3U8_Expires, VttData);
                if(!M3U8_MD5) {
                    console.log('获取 M3U8_MD5 失败');
                    $M3U8Btn.text('获取 M3U8_MD5 失败').css({'width':'230px'});
                    u.layer.tips('正在重试', $M3U8Btn);
                    setTimeout(ajaxGetID, 2000);
                    return false;
                }

                //字幕
                if(s.search(/\|vtt\|/im)===-1) $zmBtn.text('无字幕文件');
                console.log('M3U8_Hash.length', '找到', M3U8_Hash.length, '个Hash');
                switch(M3U8_Hash.length) {
                    case 2:
                        $.each(M3U8_Hash, function(i,Hash){
                            CheckVtt(Hash, M3U8_MD5);
                        });
                        break;
                    case 1:
                        CheckVtt(M3U8_Hash.toString(), M3U8_MD5, 'M3U8'); //直接跳过 VTT 检测
                        break;
                    case 0:
                        $M3U8Btn.text('未找到资源').css({'width':'150px'});
                }
                //"https://p2.japronx.com/output/cd8af61314a5caecd66a0372338e0403/index.m3u8?md5=u3OPufoTm5IIvT3IUFUWzg&expires=1558580690
            },
            'error' : function(e){
                console.log('$ error:', e);
            }
        });
    }
    ajaxGetID();

    function CheckVtt(Hash, M3U8_MD5, HashType){
        var CheckM3U8=function(){
            $M3U8Btn.text('正在获取 m3u8 地址').css({'width':'230px'});;
            u.layer.tips('正在获取 m3u8 地址', '#m3u8', {
                tips:1,
                //tipsMore: true,
                time: 10000
            });
            JaPronX.CheckUrl("https://"+PlayServer+".japronx.com/output/"+Hash+"/index.m3u8?md5="+M3U8_MD5+"&expires="+M3U8_Expires, function(e){
                console.log('CheckM3U8:', Hash, e);
                VideoUrl="https://"+PlayServer+".japronx.com/output/"+Hash+"/index.m3u8?md5="+M3U8_MD5+"&expires="+M3U8_Expires;
                switch(e.status) {
                    case 0:
                    case 200:
                        VideoDown(VideoUrl);
                        break;
                    default:
                        console.log('VTT 检测阶段 status:', e.status);
                }
            });
        }

        if(HashType=='M3U8') {
            VideoUrl="https://"+PlayServer+".japronx.com/output/"+Hash+"/index.m3u8?md5="+M3U8_MD5+"&expires="+M3U8_Expires;
            VideoDown(VideoUrl, 'loop');
        } else {
            if(!VttHash) { //没有 VTT Hash 记录的时候再请求
                JaPronX.CheckUrl('https://'+host+'/upload/admin/'+VttData+'/'+Hash+'.vtt',function(e){
                    //console.log(Hash, e);
                    switch(e.status) {
                        case 200: //如果有字幕,显示字幕按钮
                            VttHash=Hash; //记录 VTT Hash
                            VideoSubUrl='https://'+host+'/upload/admin/'+VttData+'/'+Hash+'.vtt';
                            $zmBtn.text('下载字幕').css({'color':'black'}).attr({'download':VideoID+'.vtt', 'href':VideoSubUrl});
                            break;
                        case 404: //如果没有字幕,校验是否为视频地址
                            CheckM3U8();
                            break;
                        default:
                            console.log('字幕请求状态:', e.status);
                    }
                });
            } else if(VttHash!==Hash) {//校验是否为视频地址
                CheckM3U8();
            } else {
                console.log('VttHash 已记录:', VttHash);
            }
        }
    }

    function VideoDown(VideoUrl, CheckMode){
        console.log(VideoUrl, CheckMode);
        JaPronX.CheckUrl(VideoUrl, function(e){//M3U8
            //console.log('load: ', e.status, VideoUrl, e);
            switch(e.status){
                case 0:
                case 200:
                    $M3U8Btn.attr({'href':VideoUrl, 'title':VideoID, 'target':'blank'}).text('M3U8').css({'width':'100px'});
                    $PotBtn.css({'color':'black'}).attr({'href':'potplayer://'+VideoUrl});
                    u.layer.tips('M3U8 地址已刷新', '#m3u8', {
                        tips:1,
                        //tipsMore: true,
                        time: 60000
                    });

                    GM_notification('点击消息复制地址','JaponX M3U8地址已刷新','',function(e){
                        GM_setClipboard(VideoUrl);
                    });

                    M3U8TimeOut=setTimeout(function(){
                        $M3U8Btn.attr({'href':'javascript:void(0)'}).text('链接已失效,点击刷新').css({'width':'230px'});
                        JaPronX.newM3U8();
                    }, 60*1000);
                    JaPronX.CheckVTT();  //检测当前视频是否有字幕,并tips提示
                    break;
                case 404:
                    if(CheckMode=='loop') {
                        JaPronX.CheckTime();
                    } else {
                        $M3U8Btn.text('404');
                    }
                    break;
                default:
                    console.log('m3u8 ajax error: ', e.status, e);
                    $M3U8Btn.text('获取失败').css({'width':'120px'}).click(function(){
                        JaPronX.newM3U8();
                    });
                    break;
            }
        });
    }
})();