Greasy Fork

Greasy Fork is available in English.

多瑙影院去广告 & 增强

多瑙网站视频与网站广告去除,以及其他增强功能。

目前为 2017-12-24 提交的版本,查看 最新版本

// ==UserScript==
// @name         多瑙影院去广告 & 增强
// @namespace    moe.jixun.dn-noad
// @version      1.8
// @description  多瑙网站视频与网站广告去除,以及其他增强功能。
// @author       Jixun Moe<https://jixun.moe/>
// @include      http://*.dnvod.eu/*
// @include      https://*.dnvod.eu/*
// @include      http://*.dnvod.tv/*
// @include      https://*.dnvod.tv/*
// @include      http://*.duonao.tv/*
// @include      https://*.duonao.tv/*
// @grant        none
// @compatible   Firefox  GreaseMonkey < 4
// @compatible   Chrome   TamperMonkey
// @compatible   Opera    ViolentMonkey
// @run-at       document-start
// ==/UserScript==

const MOCKED_UA = "Mozilla/5.0 (iPad; CPU OS 9_3_2 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13F69 Safari/601.1";

const _reqH = XMLHttpRequest.prototype.setRequestHeader;
const _send = XMLHttpRequest.prototype.send;
const _open = XMLHttpRequest.prototype.open;

const blacklist = [
    "/template/popup.html",
    "/template/slider.html",
];

function check(url, rule) {
    if (typeof rule === "string") {
        return url.toLowerCase().includes(rule.toLowerCase());
    } else if (typeof rule === "function") {
        return rule(url);
    } else if (rule instanceof RegExp) {
        return rule.test(url);
    }

    console.error("Unknown rule: ", rule);
}

XMLHttpRequest.prototype.send = function (payload) {
    if (typeof payload === "string") {
        if (payload.includes("action=PublicRedirect")) {
            return ;
        }
    }

    return _send.apply(this, arguments);
};

XMLHttpRequest.prototype.open = function (method, url) {
    const xhr = this;
    const strUrl = String(url);
    const block = blacklist.reduce(function (block, rule) {
        return block || check(strUrl, rule);
    }, false);
    console.debug("OPEN(%s, %s) blocked: (%s)", method, url, block);

    if (block) {
        this.send = function () {
            setTimeout(function () {
                ctx.onerror.call(ctx);
            }, 300);
        };
    } else {
        const result = _open.apply(this, arguments);
        // Firefox 43+ 支持修改 UA
        if (url.includes("/Movie/GetResource.ashx")) {
            _reqH.call(this, "User-Agent", MOCKED_UA);
        }
        return result;
    }
};

const w = window;

const each = Array.prototype.forEach;

function remove (el) {
    if (el && el.parentNode) el.parentNode.removeChild(el);
}

function playNextEp () {
    let query = location.search.replace(/&.+/, '');
    let currentEp = document.querySelector('.bfan-n>a[href*="' + query + '"]');
    if (!currentEp) return ; // 未找到当前播放剧集

    let nextEp = currentEp.parentNode.parentNode.parentNode.nextElementSibling;
    if (!nextEp) return ; // 未找到下一播放剧集

    nextEp = nextEp.querySelector('a');
    if (nextEp) nextEp.click(); // 切换到下一剧集
}

// 更新播放器配置
function updateConfig (config) {
    let p = config;
    p.l = p.r = p.d = p.u = p.pub_link = p.pub_surl = p.z = p.t = p.te = '';
    p.e = 6;

    let q = config.mobile;
    q.sl = q.sr = q.ste = '';

    console.info(config);
}

function removeAd() {
    var counter = 100;
    function skipAds() {
        console.info('发送跳过广告事件...');
        document.body.dispatchEvent(new CustomEvent('filterAds'));
    }

    function waitForAds() {
        if (window.loadedHandler) {
            let h = window.loadedHandler;
            window.loadedHandler = function () {
                h();
                setTimeout(skipAds, 50);
            };
            setTimeout(skipAds, 50);
        } else if (counter --> 0) {
            setTimeout(waitForAds, 200);
        } else {
            console.warn('节点获取失败;跳过。');
        }
    }
    waitForAds();
}

function removePlayerLogo () {
    // 改成内置水印也是挺恶心的。
    let ckstyle = w.ckstyle();
    ckstyle.logo = 'null';
    ckstyle.advmarquee = '';
    w.ckstyle = function () { return ckstyle; };
}


// Player AD removal.
// 劫持播放器的广告参数
var bakCallback;
var jQuery;

function performHook () {
    let theCallback = w._vp.theCallBack;
    let myCallback  = w._vp.myCallBack ;
    w._vp.theCallBack = function (v) {
        callbackHook(v);
        return theCallback(v);
    };
    w._vp.myCallBack = function (v) {
        callbackHook(v);
        return myCallback(v);
    };
}

function callbackHook(v) {
    updateConfig(v.container);
    var dl_btn = document.querySelector('a[href="#vidDownload"]');
    if (!dl_btn) {
        console.warn("未找到下载按钮。");
        return ;
    }
    if (v.http === null) {
        console.warn("缺少插件伪装 UA,无法获取下载地址。");
        dl_btn.addEventListener("click", function (e) {
            if (confirm("缺少插件伪装浏览器环境,是否阅读博客文章获取详细?")) {
                e.preventDefault();
                window.open("https://s.jixun.moe/duonao-ua");
            }
        });
        return ;
    }
    try {
        var dl_url = w.Decrypt(v.http.provider);
        dl_btn.target = '_blank';
        dl_btn.href = dl_url;
    } catch (error) {
        console.error(error);
    }
}

if (w.$) {
    console.info('late_hook');
    jQuery = w.$;
    jQuery(performHook);
} else {
    console.info('good hook');
    Object.defineProperty(w, '$', {
        get: function () { return jQuery; },
        set: function ($) {
            jQuery = $;
            let ready = $.fn.ready;
            $.fn.ready = function (fn) {
                if (fn.toString().indexOf('PlayVideo') != -1) {
                    performHook();
                }
                return ready.apply(this, arguments);
            };
        }
    });
}

addEventListener('DOMContentLoaded', function() {
    'use strict';

    const ads = window.dnpub ? `${window.dnpub.element}` : "";

    // 去广告与播放器调整
    var style = document.createElement('style');
    style.textContent = `
${ads} { display: none !important; }
.bfq { background: black; margin-top: 45px; }
.bfq-l { width: 100%; }
.bfq, .bfq-l { height: auto !important; padding: 0 !important; }
#video > #a1 { margin: auto; text-align: center; }
#bfy_title { padding: 0.3rem 1rem; height: auto;  }
.button-vip { margin-top: 0; }
#video { margin-top: 0; }
`;
    document.body.appendChild(style);

    // 删除广告元素
    const trap = document.getElementById("a1");
    if (trap) trap.className = "";
    if (ads) each.call(document.querySelectorAll(ads), remove);

    // 检测是否需要移除播放器 Logo
    if (w.ckstyle) {
        console.info('移除 Logo');
        try {
            removePlayerLogo();
        } catch (err) {
            console.info('移除 Logo 失败: ', err);
        }
    }

    // 检测是否需要实现播放下一集功能
    if (w.playerstop) {
        console.info('注册下一集事件成功。');
        window.playerstop = playNextEp;
    }

    jQuery(window).resize();
});