【问题标题】:How to call this YouTube function from Greasemonkey?如何从 Greasemonkey 调用这个 YouTube 功能?
【发布时间】:2013-01-08 17:03:04
【问题描述】:

我正在尝试使用 Greasemonkey 显示视频的观看时间提醒。

My script:

// ==UserScript==
// @name        Time YouTube
// @description Does not work ! Help !
// @namespace   time_youtube
// @include     *youtube.com/watch*
// @grant       GM_setValue
// @icon        http://aux3.iconpedia.net/uploads/520882026785186105.png
// @version     1.3
// ==/UserScript==

ytplayer        = document.getElementById ("movie_player");
var time        = document.createElement ('a');
time.innerHTML  = '<a style="position: fixed; top: 200px; left: 3px; color:black;">Time</a>';

//time.addEventListener ('click', function(){GM_setValue('url_time',(document.location.href) + '&t=' + (ytplayer.getCurrentTime()));}, false);
time.addEventListener ('click',
    function () {
        alert (ytplayer.getCurrentTime() );
    },
    false
);

document.body.appendChild (time);


但这不起作用。

你能帮帮我吗?谢谢!

【问题讨论】:

    标签: javascript youtube youtube-api greasemonkey


    【解决方案1】:

    由于各种安全和范围问题,您无法在 Greasemonkey 脚本范围内运行 ytplayer.getCurrentTime()

    同样,click 事件处理程序必须在目标页面的范围内运行才能访问该函数。尝试不这样做会产生undefinedError: Bad NPObject as private data! 的组合。

    这意味着您必须为您的时间按钮“注入”click 处理程序。
    但首先,还有几个问题需要考虑:

    1. Youtube 和大多数 Google 网站广泛使用 &lt;iframe&gt;s。为避免多次执行脚本时出现问题,请使用window.top === window.self 等检查来确保脚本仅在您所定位的框架或包含页面中运行。
    2. 尽可能避免使用innerHTML 和内联样式。这将使代码更易于维护,在许多情况下速度更快,并且不太可能触发意外的副作用。

    将所有这些放在一起,这是您重构的完整脚本

    // ==UserScript==
    // @name        Time YouTube
    // @description Does not work ! Help !
    // @namespace   time_youtube
    // @include     *youtube.com/watch*
    // @icon        http://aux3.iconpedia.net/uploads/520882026785186105.png
    // @grant       GM_setValue
    // @grant       GM_addStyle
    // @version     1.3
    // ==/UserScript==
    
    //-- Only run in the top page, not the various iframes.
    if (window.top === window.self) {
        var timeBtn         = document.createElement ('a');
        timeBtn.id          = "gmTimeBtn";
        timeBtn.textContent = "Time";
        //-- Button is styled using CSS, in GM_addStyle, below.
    
        document.body.appendChild (timeBtn);
    
        addJS_Node (null, null, activateTimeButton);
    }
    
    function activateTimeButton () {
        var timeBtn = document.getElementById ("gmTimeBtn");
        if (timeBtn) {
            timeBtn.addEventListener ('click',
                function () {
                    var ytplayer = document.getElementById ("movie_player");
                    //-- IMPORTANT:  GM_functions will not work here.
    
                    console.log ("getCurrentTime(): ", ytplayer.getCurrentTime() );
                    //alert (ytplayer.getCurrentTime() );
                },
                false
            );
        }
        else {
            alert ("Time button not found!");
        }
    }
    
    //-- Style and position our button the CSS way.
    GM_addStyle ( "                 \
        #gmTimeBtn {                \
            position:   fixed;      \
            top:        200px;      \
            left:       3px;        \
            color:      black;      \
            margin:     0;          \
            padding:    0;          \
        }                           \
    " );
    
    //-- This is a standard-ish utility function...
    function addJS_Node (text, s_URL, funcToRun, runOnLoad) {
        var D                                   = document;
        var scriptNode                          = D.createElement ('script');
        if (runOnLoad) {
            scriptNode.addEventListener ("load", runOnLoad, false);
        }
        scriptNode.type                         = "text/javascript";
        if (text)       scriptNode.textContent  = text;
        if (s_URL)      scriptNode.src          = s_URL;
        if (funcToRun)  scriptNode.textContent  = '(' + funcToRun.toString() + ')()';
    
        var targ = D.getElementsByTagName ('head')[0] || D.body || D.documentElement;
        targ.appendChild (scriptNode);
    }
    

    最后,从您的脚本来看,您似乎希望在单击该按钮时最终使用GM_setValue() 等。这需要跨范围的消息传递。 请参阅this answer 或在您进入该部分时提出新问题。

    【讨论】:

    • 非常感谢您的回复和解释。事实上,我会使用GM_setValue()。所以我必须提出一个新问题?再次感谢您:-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多