MediaWiki

Gadget-Normalizer.js

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Go to Menu → Settings (Opera → Preferences on a Mac) and then to Privacy & security → Clear browsing data → Cached images and files.
/* ************************************************************************** */
/* TITLE ******************************************************************** */
// Description: 
// Usage: 
// See also: [[Help:If any]]


const sparqlEndpoint = 'https://lingualibre.fr/bigdata/namespace/wdq/sparql';
const allSpeakersQuery = 'SELECT DISTINCT ?qid ?name ?gender ?linkedUser WHERE { ?qid prop:P2 entity:Q3. ?qid rdfs:label ?name. FILTER(LANG(?name) = "en"). ?qid prop:P11 ?linkedUser. ?qid prop:P8 ?genderId. BIND( IF( isBLANK(?genderId), \'\', ?genderId ) as ?gender ). }';
const allowedLicenses = [ 'cc-by-sa-4.0', 'cc-by-sa-3.0', 'cc-by-4.0', 'cc-by-3.0', 'cc-zero' ];
rw = mw.recordWizard;

/**
 * MRecord
 */

var MRecord = function( qid ) {
    console.log( 'aaa' );
    rw.Record.call( this, '' );

    this.qid = qid;
    console.log( 'bbb' );
    this.wbItem = new rw.wikibase.Item( this.qid );
}
OO.inheritClass( MRecord, rw.Record );

MRecord.prototype.setData = function( filename, transcription, qualifier, langQid, speakerQid, date ) {
    var word = transcription;
    if ( qualifier !== null ) {
        word += ' (' + qualifier + ')';
    }

	this.filename = filename;
	this.fileextension = filename.split( '.' ).pop();
    this.word = word;
    this.transcription = transcription;
    this.qualifier = qualifier;
    this.langQid = langQid;
    this.speakerQid = speakerQid;
    this.date = date;

    return true;
}

MRecord.prototype.fetchData = async function( api ) {
    var filename, langQid, speakerQid, date, transcription, qualifierStatements, qualifier;

    await this.wbItem.getFromApi( api );

    filename = this.wbItem.getStatements( rw.config.properties.audioRecord )[ 0 ].getValue();
    langQid = this.wbItem.getStatements( rw.config.properties.spokenLanguages )[ 0 ].getValue();
    speakerQid = this.wbItem.getStatements( rw.config.properties.locutor )[ 0 ].getValue();
    date = new Date( this.wbItem.getStatements( rw.config.properties.date )[ 0 ].getValue().time.slice( 1 ) );
    transcription = this.wbItem.getStatements( rw.config.properties.transcription )[ 0 ].getValue();

    qualifierStatements = this.wbItem.getStatements( rw.config.properties.qualifier );
    if ( qualifierStatements !== null ) {
        qualifier = qualifierStatements[ 0 ].getValue();
    } else {
        qualifier = null;
    }

    this.setData( filename, transcription, qualifier, langQid, speakerQid, date );
};

MRecord.prototype.updateLocalItem = async function( api ) {
    // Update local item
    this.fillWbItem();

    return await this.wbItem.createOrUpdate( api, true ).then(
        function() { return true },
        function() { return false }
    );
};





/**
 * LLNormalizer
 */

var LLNormalizer = function () {
    this.api = new mw.Api();
    this.commonsApi = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php', {
        anonymous: true,
        parameters: { origin: '*' },
        ajax: { timeout: 10000 }
    } );
};

LLNormalizer.prototype.getAllSpeakers = async function() {
    var speaker, qid,
        response = await $.post( sparqlEndpoint, { format: 'json', query: allSpeakersQuery } );

    this.speakers = {};
	for ( i = 0; i < response.results.bindings.length; i++ ) {
	    speaker = response.results.bindings[ i ];
	    qid = speaker.qid.value.split( '/' ).pop();
	    this.speakers[ qid ] = {
	        qid: qid,
	        name: speaker.name.value,
	        gender: speaker.gender.value.split( '/' ).pop(),
	        linkedUser: speaker.linkedUser.value,
	    };
	}
};

LLNormalizer.prototype.process = async function( qids, updateLocalItem, updateDescriptionOnCommons, renameOnCommons ) {
    var i, record;

    if ( !Array.isArray( qids ) ) {
        qids = [ qids ];
    }

    for ( i in qids ) {
        record = new MRecord( qids[ i ] );
        await record.fetchData( this.api );

        // Set global variable to the apropriate value
        rw.metadatas.language = record.langQid;
        rw.metadatas.locutor = this.speakers[ record.speakerQid ];
        mw.config.set( 'wgUserName', this.speakers[ record.speakerQid ].linkedUser );

        // Get the license from the description on Commons
        // If the file description doesn't contain the Lingua Libre template,
        // the returned value will be false, blocking any changes on this file
        if ( updateDescriptionOnCommons || renameOnCommons ) {
            rw.metadatas.license = await this.getLicense( record );
        }

        if ( updateLocalItem ) {
            await record.updateLocalItem( this.api );
        }
        if ( updateDescriptionOnCommons && rw.metadatas.license !== false ) {
            await this.updateDescriptionOnCommons( record );
        }
        if ( renameOnCommons && rw.metadatas.license !== false ) {
            await this.renameOnCommons( record );
        }
    }
};

LLNormalizer.prototype.getLicense = async function( record ) {
    var i, wikitext,
        license = false,
        response = await this.commonsApi.get( {
	        "action": "query",
	        "format": "json",
	        "prop": "revisions",
	        "titles": "File:" + record.filename,
	        "formatversion": "2",
	        "rvprop": "content",
	        "rvslots": "main"
        } );

    wikitext = response.query.pages[ 0 ].revisions[ 0 ].slots.main.content;
    if ( wikitext.indexOf( '{{Lingua Libre record' ) === -1 ) {
        return false;
    }

    for ( i in allowedLicenses ) {
        if ( wikitext.indexOf( '{{' + allowedLicenses[ i ] ) !== -1 ) {
            license = allowedLicenses[ i ];
            break;
        }
    }

    return license;
};

LLNormalizer.prototype.updateDescriptionOnCommons = async function( record ) {
    var newWikitext = record.getText();

    return await this.api.postWithToken( 'csrf', {
        action: 'post-to-commons',
        request: JSON.stringify( {
	        "action": "edit",
	        "format": "json",
	        "title": 'File:' + record.filename,
	        "text": newWikitext,
	        "formatversion": "2"
        } )
    } );
};

LLNormalizer.prototype.renameOnCommons = async function( record ) {
    console.log( record.filename )
    console.log( record.getFilename() )
    if ( record.filename === record.getFilename() ) {
        return false;
    }

    return await this.api.postWithToken( 'csrf', {
        action: 'post-to-commons',
        request: JSON.stringify( {
	        "action": "move",
	        "format": "json",
	        "from": 'File:' + record.filename,
	        "to": 'File:' + record.getFilename(),
	        "reason": "normalize",
	        "movetalk": 1,
	        "ignorewarnings": 1
        } )
    } );
};


/*
normalizer = new LLNormalizer();
await normalizer.getAllSpeakers();
await normalizer.process( [ 'Q651', 'Q652', 'Q653' ], true, true, true );
*/