User:Gary/automatic article lead image.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
Documentation for this user script can be added at User:Gary/automatic article lead image. |
// AUTOMATIC ARTICLE LEAD IMAGE
//
// Description: Adds a lead image to biographies that don't have lead images.
$(() => {
// Check if ran.
if (window.autoLeadImage) {
return;
}
// Set running.
window.autoLeadImage = true;
// This API key is IP-restricted, so this script won't work for other people.
const googleApiKey = 'AIzaSyBuXFJn7vNI1JYqe1GQx2i-JhH4sI7JGKk';
// eslint-disable-next-line complexity
function init() {
const enableAutomaticLeadImage = () => {
if (
window.mw.config.get('wgCanonicalNamespace') === '' &&
window.mw.config.get('wgAction') === 'view' &&
window.mw.util.getParamValue('disable') !== 'leadimage'
) {
return true;
}
return false;
};
const isPrintable = Boolean(window.location.href.match(/&printable=yes/));
if (!enableAutomaticLeadImage() || isPrintable) {
return false;
}
let isAPerson = false;
// eslint-disable-next-line no-restricted-syntax
for (const category of window.mw.config.get('wgCategories')) {
const cat = category.replace(/_/g, ' ');
if (
cat.indexOf('Living people') === 0 ||
cat.indexOf(' births') !== -1 ||
cat.indexOf(' deaths') !== -1
) {
isAPerson = true;
break;
}
}
if (!isAPerson || findLeadImages() === 1) {
return false;
}
const personName = window.mw.config.get('wgTitle');
const url =
`https://www.googleapis.com/customsearch/v1?q=${personName}` +
'&cx=004227430873773175363:j7_jwozfw80&imgType=face&num=1&' +
`searchType=image&key=${googleApiKey}`;
// Get the search results.
return $.get(url, (json) => {
// Get the first item's info.
const imageTitle = json.items[0].title;
const imageLink = json.items[0].link;
const imageThumbnail = json.items[0].image.thumbnailLink;
// If image does not exist, then show the Google-cached thumbnail instead.
return $.ajax({
url: imageLink,
error: () => imageResults([imageTitle, imageThumbnail]),
success: () => imageResults([imageTitle, imageLink]),
});
// We failed to get an image, so just show a placeholder.
}).fail(() =>
imageResults([
'Example',
'https://upload.wikimedia.org/wikipedia/commons/7/70/Example.png',
]),
);
}
// eslint-disable-next-line complexity, max-statements
function imageResults(results) {
let addAfter;
let colSpan;
let jumpToNav;
let newNode;
let newNodeDiv;
let parentNode;
const defaultLeadImageSize = 200;
// The title of the infobox, if there is one.
const fn = $('.fn').first();
const infobox = findLeadImages();
const imageUrl = decodeURI(results[1]);
// there is no infobox and no lead image
if (infobox === -1) {
// insert an image after the "difference" box
if ($('#difference').length) {
jumpToNav = $('#diffHeading').next();
// insert an image into the lead
} else {
jumpToNav = $('.mw-content-ltr:eq(0)')
.children()
.first();
// eslint-disable-next-line max-depth
if (jumpToNav[0].nodeName !== 'P') {
jumpToNav = jumpToNav.nextAll('p').first();
}
}
// everything else after here has parentNode as a TR
// in the infobox, there is no name formatted with microformats
} else if (!fn.length) {
parentNode = infobox
.children()
.first()
.children()
.first();
colSpan = parentNode
.children()
.first()
.attr('colspan');
addAfter = parentNode;
// there is a name formatted with microformats, in either TH or TD
} else if (fn[0].nodeName === 'TH' || fn[0].nodeName === 'TD') {
parentNode = fn.parent();
colSpan = fn.attr('colspan');
addAfter = parentNode;
// there is a name formatted with microformats, in a CAPTION
} else if (fn[0].nodeName === 'CAPTION') {
parentNode = fn
.siblings()
.last()
.children()
.first();
colSpan = parentNode
.children()
.first()
.attr('colspan');
addAfter = parentNode.prev();
if (colSpan <= 1) {
colSpan = 2;
}
// similar to the above, but it is the parent node
} else if (fn.parent()[0].nodeName === 'CAPTION') {
const table = fn.closest('table');
parentNode = table.find('tr').first();
colSpan = table
.find('th')
.first()
.attr('colspan');
addAfter = $();
// standard infobox with no microformats
} else {
parentNode = fn.parent().parent();
if (parentNode[0].nodeName !== 'TR') {
parentNode = parentNode.parent();
}
colSpan = fn.parent().attr('colspan');
addAfter = parentNode;
}
const newNodeImage = $(
`<a class="image" href="${imageUrl}"><img alt="${
results[0]
}" src="${imageUrl}" style="width: ${defaultLeadImageSize}px;" /></a>`,
);
const newNodePreLink = $('<span>From </span>');
const newNodeLink = $(
`<a href="http://images.google.com/images?q=${window.mw.config.get(
'wgTitle',
)}">Google Images</a>`,
);
// there is no infobox and no lead image
if (infobox === -1) {
const imagePath =
'http://bits.wikimedia.org/skins-1.5/common/images/magnify-clip.png';
const magnify = $(
'<div class="magnify"><a title="" class="internal" ' +
`href="${imageUrl}"><img width="15" height="11" alt="" ` +
`src="${imagePath}"></a></div>`,
);
const newNodeCaption = $('<div class="thumbcaption"></div>')
.append(magnify)
.append(newNodePreLink)
.append(newNodeLink);
newNodeImage.addClass('thumbimage');
newNodeDiv = $(
`<div class="thumbinner" style="width: ${defaultLeadImageSize +
2}px;"></div>`,
)
.append(newNodeImage)
.append(newNodeCaption);
newNode = $('<div class="thumb tright"></div>').append(newNodeDiv);
return jumpToNav.before(newNode);
// there is an infobox with no image
}
const newNodeSpan = $('<span style="font-size: 95%;"></span>')
.append(newNodePreLink)
.append(newNodeLink);
newNodeDiv = $('<div></div>')
.append(newNodeImage)
.append('<br />')
.append(newNodeSpan);
const newNodeChild = $(
`<td colspan="${colSpan}" style="text-align: center;"></td>`,
).append(newNodeDiv);
newNode = $('<tr></tr>').append(newNodeChild);
if (addAfter.length) {
return addAfter.after(newNode);
}
return parentNode.before(newNode);
}
// eslint-disable-next-line complexity
function findLeadImages() {
const defaultImageNames = [
'File:Replace_this_image_male.svg',
'File:Replace_this_image_female.svg',
];
const infoboxes = $('.infobox');
const tocColors = $('.toccolours');
let infoboxImages = false;
// get images in infoboxes
if (infoboxes.length) {
const $images = $('.image', infoboxes.first());
// Remove default images.
$images.each((index, element) => {
const $image = $(element);
if (defaultImageNames.indexOf($image.attr('href')) > -1) {
$image.remove();
}
});
// Running this again because we may have removed some images.
infoboxImages = $('.image', infoboxes.first());
} else if (tocColors.length) {
infoboxImages = $('.image', tocColors.first());
}
// there is more than one image in infoboxes
if (infoboxImages.length) {
return 1;
}
// there is an infobox with no image
if (infoboxImages.length === 0) {
return infoboxes.first();
}
// There are no infoboxes. Check if we are viewing a diff first
let node;
if ($('table.diff').length) {
node = $('h2.diff-currentversion-title:eq(0)').next();
} else {
node = $('.mw-content-ltr:eq(0)')
.children()
.first();
}
while (
node.length &&
node.attr('id') !== 'section-1' &&
!node.hasClass('printfooter')
) {
// there is a lead image
if (
(node[0].nodeName === 'P' || node[0].nodeName === 'DIV') &&
(node
.children()
.first()
.hasClass('image') ||
(node.children().eq(1) &&
node
.children()
.first()
.hasClass('thumbinner')))
) {
return 1;
}
node = node.next();
}
// there are no lead images
return -1;
}
init();
});