User:Gary/automatic article lead image.js
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.
// 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();
});