משתמש:Tomer T/העלאת תמונות.js
מראה
הערה: לאחר הפרסום, ייתכן שיהיה צורך לנקות את זיכרון המטמון (cache) של הדפדפן כדי להבחין בשינויים.
- פיירפוקס / ספארי: להחזיק את המקש Shift בעת לחיצה על טעינה מחדש (Reload) או ללחוץ על צירוף המקשים Ctrl-F5 או Ctrl-R (במחשב מק: ⌘-R).
- גוגל כרום: ללחוץ על צירוף המקשים Ctrl-Shift-R (במחשב מק: ⌘-Shift-R).
- אדג': להחזיק את המקש Ctrl בעת לחיצה על רענן (Refresh) או ללחוץ על צירוף המקשים Ctrl-F5.
mw.loader.using(['mediawiki.api']).then(function () {
$(function () {
var title = mw.config.get('wgPageName');
let templates = {
'Non-free film poster': 'כרזת סרט',
'Non-free album cover': 'עטיפת אלבום',
'Non-free logo': 'לוגו',
'Non-free video cover': 'כרזת סרט',
'Non-free use rationale book cover': 'עטיפת ספר',
'Non-free book cover': 'עטיפת ספר',
'Non-free poster': 'כרזת סרט',
'Non-free movie poster': 'כרזת סרט',
'Non-free video game cover': 'עטיפת אלבום',
'Non-free game cover': 'עטיפת אלבום',
'Non-free title-card': 'צילום מסך',
'Non-free television screenshot': 'צילום מסך',
'Non-free video game screenshot': 'צילום מסך',
'Non-free game screenshot': 'צילום מסך',
'Non-free board game cover': 'עטיפת אלבום',
'Non-free web screenshot': 'צילום מסך',
'Non-free computer icon': 'לוגו',
'Non-free film screenshot': 'צילום מסך',
'Non-free fair use in': 'עטיפת אלבום',
'Non-free symbol': 'לוגו'
};
let infoTemplates = ['סרט', 'אלבום', 'סינגל', 'חברה מסחרית', 'תוכנית טלוויזיה', 'ספר', 'משחק', 'דמות בדיונית'];
function getEnglishWikipediaTitle(title) {
return new Promise((resolve, reject) => {
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
data: {
action: 'query',
prop: 'langlinks',
titles: title,
lllang: 'en', // Looking for the English version
format: 'json'
},
dataType: 'json',
}).done(function(data) {
var pages = data.query.pages;
var englishTitle = null;
for (const [page, pageValue] of Object.entries(pages)) {
if (pageValue.langlinks && pageValue.langlinks.length > 0) {
englishTitle = pageValue.langlinks[0]['*'];
break;
}
}
if (englishTitle) {
resolve(englishTitle);
} else {
alert('לא נמצא ערך מקביל באנגלית');
reject(new Error('English Wikipedia title not found'));
}
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to fetch data: ' + textStatus));
});
});
}
function getImageTitlesFromArticle(title) {
return new Promise((resolve, reject) => {
let imageTitles = [];
let url = 'https://en.wikipedia.org/w/api.php';
function fetchImages(continueToken) {
$.ajax({
url: url,
data: {
action: 'query',
prop: 'images',
titles: title,
format: 'json',
origin: '*',
imcontinue: continueToken || undefined
},
dataType: 'json',
}).done(function(data) {
var pages = data.query.pages;
for (const pageId in pages) {
if (pages[pageId].images) {
imageTitles = imageTitles.concat(pages[pageId].images.map(img => img.title));
}
}
if (data.continue && data.continue.imcontinue) {
fetchImages(data.continue.imcontinue); // Fetch the next set of images
} else {
if (imageTitles.length > 0) {
resolve(imageTitles);
} else {
alert('לא נמצאו תמונות בערך באנגלית');
reject(new Error('No images found'));
}
}
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to fetch data: ' + textStatus));
});
}
fetchImages(); // Initial call to fetch images
});
}
function getNonCommonsImagesWithTemplates(imageTitles) {
return new Promise((resolve, reject) => {
$.ajax({
url: 'https://en.wikipedia.org/w/api.php',
data: {
action: 'query',
titles: imageTitles.join('|'),
prop: 'imageinfo|revisions',
iiprop: 'imagerepository',
rvprop: 'content',
format: 'json',
origin: '*'
},
dataType: 'json',
}).done(function(data) {
var pages = data.query.pages;
var imagesWithTemplates = [];
for (const pageId in pages) {
var page = pages[pageId];
if (page.imagerepository === 'local') {
if (page.revisions && page.revisions.length > 0) {
var content = page.revisions[0]['*'];
var foundTemplates = Object.keys(templates).filter(template => {
// Regex for case-insensitive matching, allowing for optional spaces
// before and after the template name, starting with {{ and ending with | or }}
var regex = new RegExp(`{{\\s*${template}\\s*(\\||}})`, 'i');
return regex.test(content);
});
if (foundTemplates.length > 0) {
imagesWithTemplates[page.title] = foundTemplates;
}
}
}
}
resolve(imagesWithTemplates);
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to fetch data: ' + textStatus));
});
});
}
function fetchImageUrls(imageTitles) {
return new Promise((resolve, reject) => {
$.ajax({
url: 'https://en.wikipedia.org/w/api.php',
data: {
action: 'query',
titles: imageTitles.join('|'),
prop: 'imageinfo',
iiprop: 'url',
iiurlwidth: 200, // Thumbnail width
iiurlheight: 200, // Thumbnail height
format: 'json',
origin: '*'
},
dataType: 'json',
}).done(function(data) {
var pages = data.query.pages;
var urls = [];
for (const pageId in pages) {
var page = pages[pageId];
if (page.imageinfo && page.imageinfo.length > 0) {
urls.push({
title: page.title,
url: page.imageinfo[0].url
});
}
}
resolve(urls);
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to fetch urls: ' + textStatus));
});
});
}
function createImageSelectionDialog(imagesWithTemplates, imageUrls) {
var selectedImages = {};
// Create dialog container
var dialogContainer = $('<div>', {
id: 'thumbnail-dialog',
title: 'בחירת תמונות להעלאה'
});
// Create content area
var content = $('<div>', { id: 'thumbnail-content' });
imageUrls.forEach(function(image, index) {
var imgElement = $('<img>')
.attr('src', image.url)
.attr('alt', image.title)
.addClass('thumbnail')
.css({ maxWidth: '200px', maxHeight: '200px', margin: '5px' });
var checkbox = $('<input>')
.attr('type', 'checkbox')
.attr('id', 'checkbox-' + index)
.css({ marginRight: '10px' })
.on('change', function() {
if (this.checked) {
selectedImages[image.title] = {url: image.url, template: imagesWithTemplates[image.title][0]};
} else {
delete selectedImages[image.title];
}
});
var label = $('<label>')
.attr('for', 'checkbox-' + index)
.text(image.title)
.css({ display: 'block', marginBottom: '10px' });
var imageContainer = $('<div>').append(checkbox, imgElement, label);
content.append(imageContainer);
});
// Append content to dialog
dialogContainer.append(content);
// Append the dialog to the body
$('body').append(dialogContainer);
// Initialize jQuery UI dialog
$('#thumbnail-dialog').dialog({
autoOpen: false,
width: 600,
height: 400,
modal: true,
buttons: {
Close: function() {
$(this).dialog('close');
},
Select: function() {
console.log('Selected Images:', selectedImages);
handleSelectedImages(selectedImages);
$(this).dialog('close');
}
},
close: function() {
// Remove the dialog from DOM after closing
$(this).dialog('destroy').remove();
}
}).dialog('open');
}
function downloadImageData(imageInfos) {
return new Promise((resolve, reject) => {
let downloadedImages = {};
let promises = [];
imageInfos.forEach(image => {
let imageUrl = image.url;
let filename = image.title.replace('File:', ''); // Clean up the filename
let fetchPromise = fetch(imageUrl)
.then(response => response.blob())
.then(blob => {
return new Promise((res, rej) => { // Return a new promise from the FileReader operation
let reader = new FileReader();
reader.onloadend = () => {
downloadedImages[filename] = {data: reader.result, template: image.template}; // base64 data URL
res(); // Resolve the promise after setting the property
};
reader.onerror = rej; // Reject on error
reader.readAsDataURL(blob);
});
})
.catch(reject);
promises.push(fetchPromise);
});
Promise.all(promises)
.then(() => resolve(downloadedImages))
.catch(reject);
});
}
function getText(filename, template) {
var title_simple = title.replaceAll('_', ' ');
var text = `== תקציר ==\n{{מידע\n|תיאור=`;
hebrewTemplate = templates[template];
var license = null;
var desc = `[[${title_simple}]]`;
switch (hebrewTemplate) {
case ("כרזת סרט"):
license = `{{כרזת סרט|${title_simple}}}`;
desc = `כרזת ${desc}`;
break
case ("עטיפת אלבום"):
license = `{{עטיפת אלבום|${title_simple}}}`;
desc = `עטיפת ${desc}`;
break
case ("לוגו"):
license = `{{לוגו|${title_simple}}}`;
desc = `לוגו ${desc}`;
break
case ("עטיפת ספר"):
license = `{{עטיפת ספר|${title_simple}}}`;
desc = `עטיפת ${desc}`;
break
case ("צילום מסך"):
license = `{{צילום מסך|${title_simple}}}`;
desc = `צילום מתוך ${desc}`;
break
}
text += desc;
text += `\n|מקור={{EN|שם=${filename}|יש רישיון=כן}}\n|תאריך יצירה=\n|יוצר=\n|אישורים והיתרים=`;
text += license;
text += "\n|גרסאות אחרות=\n}}\n<!-- קובץ זה הועלה באמצעות הסקריפט [[משתמש:Tomer T/העלאת תמונות.js]] -->";
return text;
}
function uploadImage(filename, fileInfo, token) {
return new Promise((resolve, reject) => {
var formData = new FormData();
var fileContent = fileInfo.data;
var template = fileInfo.template;
let text = getText(filename, template);
console.log('text:', text);
// Convert the base64 string back to a Blob
const byteString = atob(fileContent.split(',')[1]); // Split base64 header and data
const mimeString = fileContent.split(',')[0].split(':')[1].split(';')[0];
const arrayBuffer = new ArrayBuffer(byteString.length);
const uint8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < byteString.length; i++) {
uint8Array[i] = byteString.charCodeAt(i);
}
const fileBlob = new Blob([arrayBuffer], { type: mimeString });
// Handle filename length and append "(Hebrew wiki upload)" if necessary
var filename_to_use = filename;
const fileExtension = filename.substring(filename.lastIndexOf('.'));
if (filename_to_use.length <= 12) {
filename_to_use = filename.substring(0, filename.lastIndexOf('.')) +
" (Hebrew wiki upload)" +
fileExtension;
}
// Check if the file already exists
checkSomeFileExists([filename, filename_to_use]).then((exists) => {
if (exists) {
alert(`שגיאה: הקובץ כבר קיים: ${exists}.`);
console.warn(`File already exists: ${exists}`);
reject(new Error(`File already exists: ${exists}`));
} else {
// Proceed with upload if the file does not exist
formData.append('comment', 'Uploaded via script');
formData.append('text', text);
formData.append('action', 'upload');
formData.append('filename', filename_to_use);
formData.append('file', fileBlob, filename_to_use);
formData.append('token', token);
formData.append('format', 'json');
formData.append('ignorewarnings', 'true'); // Ignore warnings, e.g. if a file with the same name was previously deleted
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
method: 'POST',
data: formData,
processData: false,
contentType: false,
xhrFields: {
withCredentials: true
}
}).done(function(data) {
if (data.upload && data.upload.result === 'Success') {
resolve([data.upload, filename_to_use]);
} else if (data.upload && data.upload.result === 'Warning') {
if (data.upload.warnings.exists) {
alert(`שגיאה: הקובץ כבר קיים: ${data.upload.warnings.exists}.`);
console.warn(`File already exists: ${data.upload.warnings.exists}`);
reject(new Error(`File already exists: ${data.upload.warnings.exists}`));
} else if (data.upload.warnings.nochange) {
console.warn(`No change in file detected: ${data.upload.warnings.nochange.timestamp}`);
resolve([data.upload, filename_to_use]);
} else {
reject(new Error('Upload warning: ' + JSON.stringify(data.upload.warnings)));
}
} else {
reject(new Error('Upload failed: ' + JSON.stringify(data)));
}
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to upload image: ' + textStatus));
});
}
}).catch(error => {
reject(new Error('Error checking file existence: ' + error));
});
});
}
function checkSomeFileExists(filenames) {
return new Promise((resolve, reject) => {
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
data: {
action: 'query',
titles: filenames.map(name => `File:${name}`).join('|'),
format: 'json'
},
dataType: 'json',
success: function(data) {
var pages = data.query.pages;
for (var pageId in pages) {
if (pages[pageId].missing === undefined) {
// File exists
resolve(pages[pageId].title);
return;
}
}
// No files exist
resolve(null);
},
error: function(jqXHR, textStatus, errorThrown) {
reject(new Error('Error checking file existence: ' + textStatus));
}
});
});
}
async function handleSelectedImages(selectedImages) {
try {
if (Object.entries(selectedImages).length === 0) {
console.log('No images to handle');
return;
}
console.log("Processing selected images:", selectedImages);
// Fetch CSRF token
let csrfToken = await getCsrfToken();
console.log('CSRF Token:', csrfToken);
// Download image data for selected images
let imageInfos = Object.entries(selectedImages).map(([title, imageDict]) => ({ title, url: imageDict.url, template: imageDict.template }));
let downloadedImagesResult = await downloadImageData(imageInfos);
console.log('Downloaded Images Data:', downloadedImagesResult);
const downloadedKeys = Object.keys(downloadedImagesResult);
if (downloadedKeys.length === 0) {
console.error('No images downloaded.');
return;
}
// Collect the URLs of the uploaded files
let uploadedFileNames = [];
// Upload the images to Hebrew Wikipedia
for (const [filename, fileInfo] of Object.entries(downloadedImagesResult)) {
console.log('Uploading:', filename);
let result = await uploadImage(filename, fileInfo, csrfToken);
console.log('Upload result:', result[0]);
if (result[0].imageinfo && result[0].imageinfo.descriptionurl) {
uploadedFileNames.push(result[1]);
}
}
// Format the links as a string
//let links = uploadedFileLinks.map((url, index) => `<a href="${url}" target="_blank">${index}</a>`).join('<br>');
// Alert the links to the uploaded files
alert(`כל הקבצים הועלו בהצלחה:\n\n${uploadedFileNames}`);
// Only suggest to edit the page if one file was uploaded
if (uploadedFileNames.length === 1) {
editPageAfterUpload(uploadedFileNames[0]);
}
} catch (error) {
console.error('Error during handling selected images:', error.message);
}
}
function getCsrfToken() {
return new Promise((resolve, reject) => {
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
method: 'POST',
data: {
action: 'query',
meta: 'tokens',
type: 'csrf',
format: 'json'
},
dataType: 'json',
xhrFields: {
withCredentials: true
}
}).done(function(data) {
resolve(data.query.tokens.csrftoken);
}).fail(function(jqXHR, textStatus, errorThrown) {
reject(new Error('Failed to get CSRF token: ' + textStatus));
});
});
}
function editPageAfterUpload(imageName) {
// Ask user for confirmation
var addImage = confirm("האם ברצונך להוסיף את התמונה לערך בצורה אוטומטית?");
if (!addImage) {
return;
}
// Fetch the page content
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
data: {
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: title,
format: 'json'
},
dataType: 'json',
success: function(data) {
var pages = data.query.pages;
var pageId = Object.keys(pages)[0];
var pageContent = pages[pageId].revisions[0]['*'];
// Check for known templates in the content
var templateFound = null;
infoTemplates.forEach(function(template) {
var regex = new RegExp(`\\{\\{\\s*${template}\\s*(\\||}})`, 'i');
if (regex.test(pageContent)) {
templateFound = template;
}
});
var newContent = '';
var add_to_beginning = false;
if (templateFound) {
// Handle the case where there is an existing |תמונה= field
var imageFieldPattern = new RegExp(`(\\|\\s*תמונה\\s*=[ ]?)(\\s*)([^|}]*)`, 'i');
if (imageFieldPattern.test(pageContent)) {
var match = pageContent.match(imageFieldPattern);
var existingImageFieldContent = match[3].trim();
if (existingImageFieldContent) {
// Already have an image under the infobox, let's add to beginning of article
add_to_beginning = true;
} else {
// Replace the empty image field with the new image
newContent = pageContent.replace(imageFieldPattern, `$1File:${imageName}$2`);
}
} else {
// Add the image to the template as a new field
newContent = pageContent.replace(
new RegExp(`\\{\\{\\s*${templateFound}\\s*(\\||}})`, 'i'),
`{{${templateFound}\n| תמונה = ${imageName}\n$1`
);
}
} else {
add_to_beginning = true;
}
// Add the image at the beginning of the article
if (add_to_beginning) {
newContent = `[[קובץ:${imageName}|שמאל|ממוזער|250px|]]\n` + pageContent;
}
// Submit the edited page content
submitPageEdit(newContent, `הוספת תמונה: [[קובץ:${imageName}]]`);
},
error: function(xhr, status, error) {
console.error('Error fetching page content:', status, error);
}
});
}
function submitPageEdit(newContent, summary) {
getCsrfToken().then(function(csrfToken) {
$.ajax({
url: mw.config.get('wgServer') + '/w/api.php',
method: 'POST',
data: {
action: 'edit',
title: title,
text: newContent,
summary: summary,
token: csrfToken,
format: 'json'
},
dataType: 'json',
success: function(data) {
if (data.edit && data.edit.result === 'Success') {
// Refresh
location.reload();
} else {
console.error('Error editing the page:', data);
alert('An error occurred while editing the page.');
}
},
error: function(xhr, status, error) {
console.error('Error editing the page:', status, error);
}
});
});
}
// Function to dynamically add a button and set up an event listener
function addButton() {
var actionsMenu = document.querySelector('#p-cactions .vector-menu-content-list');
if (actionsMenu) {
var importButton = document.createElement('li');
importButton.innerHTML = '<a href="#" id="import-images-button">ייבוא תמונות</a>';
// Add margin between items if needed (based on existing styles)
importButton.style.marginTop = '8px'; // Adjust the margin as needed
actionsMenu.appendChild(importButton); // Insert as the last item
document.getElementById('import-images-button').addEventListener('click', function (e) {
e.preventDefault();
initiateUploadProcess(); // Call your existing function to start the process
});
} else {
// Fallback: append to the body if the actions menu is not found
var fallbackButton = $('<button>', {
id: 'start-upload',
text: 'Start Upload Process'
});
$('body').append(fallbackButton);
$('#start-upload').click(initiateUploadProcess);
}
}
// Call this function to add the button when the page is ready
$(document).ready(addButton);
// Main function to initiate the upload process
async function initiateUploadProcess() {
try {
let englishWikipediaTitle = await getEnglishWikipediaTitle(title);
console.log('English Wikipedia Title:', englishWikipediaTitle);
let imageTitles = await getImageTitlesFromArticle(englishWikipediaTitle);
console.log('English Wikipedia Image titles:', imageTitles);
let imagesWithTemplates = await getNonCommonsImagesWithTemplates(imageTitles);
console.log('English Wikipedia Images with fair-use templates:', imagesWithTemplates);
if (Object.keys(imagesWithTemplates).length === 0) {
alert('לא נמצאו תמונות שימוש הוגן להעלאה.');
} else {
let imageUrls = await fetchImageUrls(Object.keys(imagesWithTemplates));
console.log('English Wikipedia Images URLs:', imageUrls);
createImageSelectionDialog(imagesWithTemplates, imageUrls);
}
} catch (error) {
console.log('Error:', error.message);
}
}
});
});