GM_xmlhttpRequest数据被放置在错误的位置

时间:2014-05-31 21:55:21

标签: javascript greasemonkey userscripts

我正在使用以下优秀用户(适用于Chrome,Chrome&#t; Tampermonkey和Firefox Greasemonkey)。它应该在每个IMDb电影链接旁边显示电影评级,但它已停止正常工作。

这是完整的脚本:

// ==UserScript==
// @name           Add IMDb rating next to all IMDb links (+voter count)
// @author         Ali
// @description    Adds movie ratings and number of voters to any IMDb link. Modified version of http://userscripts.org/scripts/show/9174
// @include        *
// @version        2013-05-12
// @namespace      http://userscripts.org/scripts/show/96884
// @grant          GM_xmlhttpRequest
// @downloadURL    http://www.alibakir.com/upload/addimdbratings.js
// @updateURL      http://www.alibakir.com/upload/addimdbratings.js
// ==/UserScript==
var IMDBpluginlinks = document.links;
var IMDBcontinueelement=document.createElement("button");
IMDBcontinueelement.innerHTML="Get rating";

function processIMDBLinks(s){
    IMDBcontinueelement.style.display = 'none';
    var r=0;
    for (IMDBi = s; IMDBi < IMDBpluginlinks.length; IMDBi++) {
        if (IMDBpluginlinks[IMDBi].href.indexOf("/title/") != -1 && IMDBpluginlinks[IMDBi].href.indexOf("imdb.") != -1){
            if(r>300){
                IMDBcontinueelement.onclick=function(){ processIMDBLinks(IMDBi); };
                IMDBcontinueelement.style.display='inline';
                IMDBpluginlinks[IMDBi].parentNode.insertBefore(IMDBcontinueelement, IMDBpluginlinks[IMDBi]);
                break;
            }
            r++;
            GM_xmlhttpRequest({
                method: 'get',
                headers: {
                },
                url: IMDBpluginlinks[IMDBi].href,
                onload: function (IMDBi){return function(result) {
                     rating = result.responseText.match(/Users rated this (.*) \(/);
                     votes = result.responseText.match(/\((.*) votes\) -/);
                     IMDBpluginlinks[IMDBi].parentNode.insertBefore(document.createElement("span"), IMDBpluginlinks[IMDBi]).innerHTML = (rating ? "<b> [" + rating[1] + " - "+votes[1]+"] </b>" : "<b style='color: red;'>[NA] </b>&nbsp;");
                }}(IMDBi)
            });
        }
    }
}
processIMDBLinks(0);


这就是an example page目前的看法:

Results being added to the wrong links


如您所见,脚本在错误的位置显示结果。

为什么它出现在错误的地方以及如何解决?

1 个答案:

答案 0 :(得分:2)

导致主要投诉的问题(导致错误的地方)是GM_xmlhttpRequest异步操作(这很好)并且onload构造不正确。

您需要将来电GM_xmlhttpRequest打包到正确的closure或在context来电中提供GM_xmlhttpRequest。 (参见下面的代码。)

有关为何需要关闭的详细信息,请参阅this answer to the same type of problem


其他重大问题包括AJAX-获取数十个不正确的链接以及在每个页面和iframe上触发。这两种方式都会使浏览器慢下来。

请勿使用@include *。即使你不介意,脚本的其他用户也会。仅为您知道有IMDB链接的网站添加@include@match行。

我以为我可能想自己使用这个脚本,所以我开始清理它。您可以阅读内联注释并与原始脚本进行比较,以了解一些较小的问题。 (不要使用onclick并始终检查match返回等。)

// ==UserScript==
// @name         add IMDb rating next to all IMDb links (+voter count)
// @description  Adds movie ratings and number of voters to any imdb link. Modified version of http://userscripts.org/scripts/show/96884
// @match        *://www.imdb.com/*
// @grant        GM_xmlhttpRequest
// ==/UserScript==

var maxLinksAtATime     = 50; //-- pages can have 100's of links to fetch. Don't spam server or browser.
var fetchedLinkCnt      = 0;

function processIMDB_Links () {
    //--- Get only links that could be to IMBD movie/TV pages.
    var linksToIMBD_Shows   = document.querySelectorAll ("a[href*='/title/']");

    for (var J = 0, L = linksToIMBD_Shows.length;  J < L;  J++) {
        var currentLink = linksToIMBD_Shows[J];

        /*--- Strict tests for the correct IMDB link to keep from spamming the page
            with erroneous results.
        */
        if (    ! /^(?:www\.)?IMDB\.com$/i.test (currentLink.hostname)
            ||  ! /^\/title\/tt\d+\/?$/i.test (currentLink.pathname)
        )
            continue;

        if (! currentLink.getAttribute ("data-gm-fetched") ){
            if (fetchedLinkCnt >= maxLinksAtATime){
                //--- Position the "continue" button.
                continueBttn.style.display = 'inline';
                currentLink.parentNode.insertBefore (continueBttn, currentLink);
                break;
            }

            fetchTargetLink (currentLink); //-- AJAX-in the ratings for a given link.

            //---Mark the link with a data attribute, so we know it's been fetched.
            currentLink.setAttribute ("data-gm-fetched", "true");
            fetchedLinkCnt++;
        }
    }
}

function fetchTargetLink (linkNode) {
    //--- This function provides a closure so that the callbacks can work correctly.

    /*--- Must either call AJAX in a closure or pass a context.
        But Tampermonkey does not implement context correctly!
        (Tries to JSON serialize a DOM node.)
    */
    GM_xmlhttpRequest ( {
        method:     'get',
        url:        linkNode.href,
        //context:    linkNode,
        onload:     function (response) {
            prependIMDB_Rating (response, linkNode);
        },
        onload:     function (response) {
            prependIMDB_Rating (response, linkNode);
        },
        onabort:     function (response) {
            prependIMDB_Rating (response, linkNode);
        }
    } );
}

function prependIMDB_Rating (resp, targetLink) {
    var isError     = true;
    var ratingTxt   = "** Unknown Error!";

    if (resp.status != 200  &&  resp.status != 304) {
        ratingTxt   = '** ' + resp.status + ' Error!';
    }
    else {
        if (/\(awaiting \d+ votes\)|\(voting begins after release\)|in development/i.test (resp.responseText) ) {
            ratingTxt   = "NR";
            isError     = false;
        }
        else {
            var ratingM = resp.responseText.match (/Users rated this (.*) \(/);
            var votesM  = resp.responseText.match (/\((.*) votes\) -/);

            if (ratingM  &&  ratingM.length > 1  &&  votesM  &&  votesM.length > 1) {
                isError     = false;
                ratingTxt   = ratingM[1] + " - " + votesM[1];
            }
        }
    }

    var resltSpan       = document.createElement ("span");
    resltSpan.innerHTML = '<b> [' + ratingTxt + '] </b>&nbsp;';

    if (isError)
        resltSpan.style.color = 'red';

    //var targetLink      = resp.context;
    //console.log ("targetLink: ", targetLink);

    targetLink.parentNode.insertBefore (resltSpan, targetLink);
}

//--- Create the continue button
var continueBttn        = document.createElement ("button");
continueBttn.innerHTML  = "Get ratings";

continueBttn.addEventListener ("click", function (){
        fetchedLinkCnt              = 0;
        continueBttn.style.display  = 'none';
        processIMDB_Links ();
    },
    false
);

processIMDB_Links ();