User:Anomie/unattributed-image-finder.js

Source: Wikipedia, the free encyclopedia.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/* If you want to use this script, simply add the following line to your [[Special:Mypage/common.js]]:
 
importScript('User:Anomie/unattributed-image-finder.js'); // Linkback: [[User:Anomie/unattributed-image-finder.js]]
 
* (Please keep the comment so I can see how many people use this). You will also want to
* add some CSS classes, such as those at [[User:Anomie/unattributed-image-finder.css]].
*/
 
/* If you want this to run "on demand" instead of on every page, set "UnattributedImageFinder=true" and
 * use addPortletLink() or the like to add a button calling UnattributedImageFinder.onDemand().
 */

var UnattributedImageFinder = {
    no_attribution_cats:[
        // en
        'Category:Cc-zero images',
        'Category:All user-created public domain images',
        'Category:Author died more than 100 years ago public domain images',
        'Category:Author died more than 70 years ago public domain images',
        'Category:Copyright holder released public domain images',
        'Category:PD OpenClipart',
        'Category:PD US no notice',
        'Category:PD US not renewed',
        'Category:PD chem',
        'Category:PD other reasons',
        'Category:PD script',
        'Category:PD tag needs updating',
        'Category:PD-link',
        'Category:Pre 1978 without copyright notice US public domain images',
        'Category:Public domain art',
        'Category:Public domain images',
        'Category:Public domain images ineligible for copyright',
        'Category:Public domain images of currency',
        'Category:Public domain images of fonts',
        'Category:Public domain music images',

        // commons
        'Category:CC-Zero',
        'Category:AIGA symbol signs',
        'Category:Anonymous work',
        'Category:CC-PD',
        'Category:CC-PD-Mark',
        'Category:CC-Zero',
        'Category:Kopimi',
        'Category:PD Flags',
        'Category:PD cartoons',
        'Category:PD coat of arms definitions',
        'Category:PD ineligible',
        'Category:PD other reasons',
        'Category:PD patents',
        'Category:PD-author',
        'Category:PD-copyright holder',
        'Category:PD-heirs',
        'Category:PD-imf.org',
        'Category:PD-link',
        'Category:PD-scan',
        'Category:PD-self',
        'Category:PD-user',
        'Category:Public domain',
        'Category:Public domain due to copyright expiration',
        'Category:Public domain images no longer eligible for claim of authorship',
        'Category:Public domain images of fonts',
        'Category:PD ancient script',
        'Category:PD chem',
        'Category:PD ineligible',
        'Category:PD ineligible OpenGeoDB',
        'Category:PD script',
        'Category:PD shape',
        'Category:PD signature',
        'Category:PD text',
        'Category:PD-Art (PD-ineligible)',
        'Category:PD-Art (PD-shape)',

        // Apparently this is ok
        'Category:Copyright by Wikimedia',
        'Category:Files copyrighted by the Wikimedia Foundation'
    ],
    rqcount:0,
    ncount:0,

    decodeImageName:function(n){
        return 'File:'+decodeURIComponent(n.replace(/_/g, ' '));
    },

    processImages:function(r,sts,xhr){
        if(!r.query || !r.query.pages) {
            if(typeof(window.console)=='undefined' || typeof(window.console.error)!='function')
                throw new Error('Bad response');
            window.console.error("Bad response", r);
            return;
        }

        var imgok=this.imgok;
        var imglist=this.imglist;
        for(var k in r.query.pages){
            var p=r.query.pages[k];
            if(typeof(p.categories)=='undefined') continue;
            var title=p.title;
            if(imgok[title]) continue;
            var cats=p.categories.map(function(c){ return c.title; });
            for(var i=0; i<cats.length; i++){
                if(UnattributedImageFinder.no_attribution_cats.indexOf(cats[i])>=0){
                    imgok[title]=true;
                    break;
                }
            }
        }

        if(r['query-continue']){
            var cc=this.rawdata;
            for(var k in r['query-continue']){
                for(var k2 in r['query-continue'][k]){
                    cc[k2]=r['query-continue'][k][k2];
                }
            }
            $.ajax({
                url:this.url,
                dataType:this.dataType,
                type:'POST',
                data:cc,
                rawdata:cc,
                imgok:imgok,
                imglist:imglist,
                success:arguments.callee,
                error:function(xhr,textStatus,errorThrown){
                    UnattributedImageFinder.rqcount--;
                    UnattributedImageFinder.doAlert();
                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);
                }
            });
            return;
        }

        for(var i=imglist.length-1; i>=0; i--){
            // Images, local or on Commons
            var m=imglist[i].src.match(/\/\/upload.wikimedia.org\/wiki[mp]edia\/(en|commons)\/(thumb\/)?[0-9a-f]\/[0-9a-f][0-9a-f]\/([^\/]+)/);
            if(!m) continue;
            var name=UnattributedImageFinder.decodeImageName(m[3]);
            if(typeof(imgok[name])=='undefined' || imgok[name]) continue;
            $(imglist[i]).addClass('unattributed-image');
            UnattributedImageFinder.ncount++;
        }

        UnattributedImageFinder.rqcount--;
        UnattributedImageFinder.doAlert();
    },

    loadCats:function(api,images,imglist){
        if(!api) api=mw.util.wikiScript('api');
        while(images.length>0){
            var imgs=images.splice(0,50);
            var imgok={};
            for(var i=0; i<imgs.length; i++){
                imgok[imgs[i]]=false;
            }
            var q={
                format:'json',
                action:'query',
                titles:imgs.join('|'),
                prop:'categories',
                cllimit:'max'
            };
            if(api != mw.util.wikiScript('api')){
                // Set origin for CORS request
                q.origin = location.protocol+'//'+location.host;
            }
            UnattributedImageFinder.rqcount++;
            $.ajax({
                url:api,
                dataType:'json',
                type:'POST',
                data:q,
                rawdata:q,
                imgok:imgok,
                imglist:imglist,
                rawcontinue:'',
                success:UnattributedImageFinder.processImages,
                error:function(xhr,textStatus,errorThrown){
                    UnattributedImageFinder.rqcount--;
                    UnattributedImageFinder.doAlert();
                    throw new Error('AJAX error: '+textStatus+' '+errorThrown);
                }
            });
        }
    },
    
    scanChildren:function(node){
        mw.loader.using('mediawiki.util', function(){
            var imgs=node.getElementsByTagName('IMG');
            var checkimgs={ en:{}, commons:{} };
            var imglist=[];
            for(var i=imgs.length-1; i>=0; i--){
                // Images, local or on Commons
                var m=imgs[i].src.match(/\/\/upload.wikimedia.org\/wiki[mp]edia\/(en|commons)\/(thumb\/)?[0-9a-f]\/[0-9a-f][0-9a-f]\/([^\/]+)/);
                if(!m) continue;
                var source=m[1];
                var name=UnattributedImageFinder.decodeImageName(m[3]);

                // Skip uses of the image on its own image page
                if(name == mw.config.get('wgPageName').replace(/_/g,' ')) continue;

                // Skip if linked to the image description page
                if(imgs[i].parentNode.nodeName=='A'){
                    var m2=imgs[i].parentNode.href.match(/\/\/en.wikipedia.org\/wiki\/File:(.*)/);
                    if(m2 && UnattributedImageFinder.decodeImageName(m2[1])==name) continue;
                }

                checkimgs[source][name]=1;
                imglist.push(imgs[i]);
            }

            UnattributedImageFinder.rqcount++;

            // Now we must load the categories for the images.
            imgs=[];
            for(var k in checkimgs.en) imgs.push(k);
            UnattributedImageFinder.loadCats(null, imgs, imglist);
            imgs=[];
            for(var k in checkimgs.commons) imgs.push(k);
            UnattributedImageFinder.loadCats('//commons.wikimedia.org/w/api.php', imgs, imglist);

            UnattributedImageFinder.rqcount--;
            UnattributedImageFinder.doAlert();
        });
    },

    onLoad:function(){
        if(window.UnattributedImageFinderOnDemand) return;
        if(window.AJAXPreview) window.AJAXPreview.AddOnLoadHook(UnattributedImageFinder.scanChildren);
        UnattributedImageFinder.onDemand();
    },
 
    onDemand:function(){
        var node=document.getElementById('wikiPreview');
        if(!node) node=document.getElementById('bodyContent');
        if(node) UnattributedImageFinder.scanChildren(node);
    },

    doAlert:function(){
        if(!window.UnattributedImageFinderAlert) return;
        if(UnattributedImageFinder.rqcount>0 || UnattributedImageFinder.ncount<=0) return;
        var d=document.createElement('DIV');
        d.className='unattributed-image-finder-notification';
        if(UnattributedImageFinder.ncount==1){
            d.appendChild(document.createTextNode("Found 1 image that appears to be unlinked but requires attribution"));
        } else {
            d.appendChild(document.createTextNode("Found "+UnattributedImageFinder.ncount+" images that appear to be unlinked but require attribution"));
        }
        d.appendChild(document.createTextNode(" "));
        var hide=document.createElement('SPAN');
        hide.appendChild(document.createTextNode('[hide]'));
        hide.style.cursor='pointer';
        $(hide).click(function(){
            d.parentNode.removeChild(d);
        });
        d.appendChild(hide);
        document.body.appendChild(d);
    }
};

if(!window.UnattributedImageFinderOnDemand) $(document).ready(UnattributedImageFinder.onLoad);