לדלג לתוכן

משתמש: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);
		    }
		}

	});
});