Greasy Fork is available in English.

YggTorrent amélioré [Edit]

Découvrez une connexion automatique, des boutons de téléchargement dans les résultats de recherche, une fonction de prévisualisation d'image des torrents au survol, et bien d'autres améliorations.

// ==UserScript==
// @name           YggTorrent amélioré [Edit]
// @match          https://*.ygg.re/*
// @version        1.24
// @author         J.H / clemente
// @license        MIT
// @description    Découvrez une connexion automatique, des boutons de téléchargement dans les résultats de recherche, une fonction de prévisualisation d'image des torrents au survol, et bien d'autres améliorations.
// @run-at         document-end
// @noframes
// @icon           https://www.google.com/s2/favicons?sz=64&domain=ygg.re
// @grant          GM.getValue
// @grant          GM.setValue
// @grant          GM.deleteValue
// @grant          GM_addStyle
// @grant          GM_xmlhttpRequest
// @namespace https://greasyfork.org/users/448067
// ==/UserScript==

(async function () {
	const CONFIG = {
		// DEBUT CONFIGURATION (Pour désactiver une option, il suffit de mettre false à la place de true)
		BETTER_DARK_THEME: false, // Thème sombre amélioré + blocage de certaines publicités recalcitrantes malgré "uBlock Origin"
		LOGIN_AUTOMATICALLY: true, // Se connecte automatiquement après avoir saisie les identifiants au moins une fois
		PREVIEWS_IMAGES_ON_HOVER: true, // Affiche une prévisualisation de l'image du torrent au survol
		PREVIEWS_IMAGES_SIZE: 250, // Taille des images de prévisualisation en pixels
		DOWNLOAD_BUTTONS_IN_RESULTS: true, // Ajoute un bouton de téléchargement dans les résultats de recherche
		HIDE_SIDEBAR: true, // Masque la barre latérale
		LARGER_NFO: true, // Agrandit la fenêtre de prévisualisation du NFO
		SEARCH_BY_LATEST_FIRST: true, // Affiche les résultats de recherche par date de publication (du plus récent au plus ancien)
		KEEP_SEARCH_WHEN_CLICKING_ON_SUBCATEGORY_ICON: true, // Garde les critères de recherche lorsqu'on clique sur une catégorie
		// FIN CONFIGURATION (Evitez de toucher au reste si vous ne savez pas ce que vous faites)
	};

	const SELECTORS = {
		REGISTER_BUTTON: '.register',
		TORRENT_NAME_LINK: 'a[id="torrent_name"]',
		RESULTS_TABLE_ROW: '.results table tbody tr',
		INPUT_USERNAME: 'input[name="id"]',
		INPUT_PASSWORD: 'input[name="pass"]',
		INPUT_SUBMIT: 'button[type="submit"]',
		LOGOUT_LINK: 'a[href="https://www.ygg.re/user/logout"]',
		NFO_MODAL: '#nfoModal',
		SEARCH_FORM: 'form.search',
		LOGIN_FORM: '.login-form',
	};

	const CONSTANTS = {
		IMAGE_MODAL_STYLE: `min-width: ${CONFIG.PREVIEWS_IMAGES_SIZE}px; max-width: ${CONFIG.PREVIEWS_IMAGES_SIZE}px;`,
		COOKIES_STORAGE_KEY: 'yggtorrent_credentials',
		MOUSEENTER_DELAY: 100,
	};

	CONFIG.BETTER_DARK_THEME && betterDarkTheme();
	CONFIG.DOWNLOAD_BUTTONS_IN_RESULTS && addDownloadButtonToTorrents();
	CONFIG.HIDE_SIDEBAR && hideSidebar();
	CONFIG.LARGER_NFO && displayLargerNfo();
	CONFIG.SEARCH_BY_LATEST_FIRST && searchByLatestFirst();
	CONFIG.KEEP_SEARCH_WHEN_CLICKING_ON_SUBCATEGORY_ICON && keepSearchWhenClickingOnSubcategoryIcon();
	//CONFIG.PREVIEWS_IMAGES_ON_HOVER && displayImageHandler();
	CONFIG.LOGIN_AUTOMATICALLY && await handleLogin();

	async function handleLogin() {
		const isNotLoggedIn = document.querySelector(SELECTORS.REGISTER_BUTTON);
		const savedCredentials = await GM.getValue(CONSTANTS.COOKIES_STORAGE_KEY);

		if (isNotLoggedIn && !savedCredentials) {
			await getCredentials();
		} else if (isNotLoggedIn && savedCredentials) {
			await autoLogin(savedCredentials);
		}
	}

	async function getCredentials() {
		try {
			const loginForm = document.querySelector(SELECTORS.LOGIN_FORM);

			if (loginForm) {
				loginForm.addEventListener('submit', async (e) => {
					e.preventDefault();
					const usernameInput = loginForm.querySelector(SELECTORS.INPUT_USERNAME);
					const passwordInput = loginForm.querySelector(SELECTORS.INPUT_PASSWORD);
					await saveCredentials(usernameInput.value, passwordInput.value);
				});
			}
		} catch (error) {
			console.error('Error getting credentials:', error);
		}
	}

	async function autoLogin(credentials) {
		try {
			const loginForm = document.querySelector(SELECTORS.LOGIN_FORM);

			if (loginForm) {
				const usernameInput = loginForm.querySelector(SELECTORS.INPUT_USERNAME);
				const passwordInput = loginForm.querySelector(SELECTORS.INPUT_PASSWORD);
				const submitButton = loginForm.querySelector(SELECTORS.INPUT_SUBMIT);

				if (usernameInput && passwordInput && submitButton) {
					usernameInput.value = credentials.username;
					passwordInput.value = credentials.password;

					submitButton.click();
				}
			}
		} catch (error) {
			console.error('Error during login:', error);
		}
	}

	const logoutLink = document.querySelector(SELECTORS.LOGOUT_LINK);
	if (logoutLink) {
		logoutLink.addEventListener('click', deleteCredentials);
	}

	async function deleteCredentials() {
		try {
			await GM.deleteValue(CONSTANTS.COOKIES_STORAGE_KEY);
		} catch (error) {
			console.error('Error deleting credentials:', error);
		}
	}

	async function saveCredentials(username, password) {
		try {
			await GM.setValue(CONSTANTS.COOKIES_STORAGE_KEY, { username, password });
		} catch (error) {
			console.error('Error saving credentials:', error);
		}
	}

/* 	function fetchImageSize(url) {
		return new Promise((resolve, reject) => {
			const img = new Image();
			img.onload = () => resolve({ width: img.width, height: img.height, url });
			img.onerror = reject;
			img.src = url;
		});
	}

	function makeGetRequest(url) {
		return new Promise((resolve, reject) => {
			GM_xmlhttpRequest({
				method: 'GET',
				url,
				onload: function (response) {
					resolve(response.responseText);
				},
				onerror: function (error) {
					reject(error);
				},
			});
		});
	}

	async function getImages(url) {
		const imageRet = [];
		try {
			const response = await makeGetRequest(url);
			const parser = new DOMParser();
			const doc = parser.parseFromString(response, 'text/html');
			if (doc.title.includes('Just a moment...')) {
				imageRet.push({
					width: 250,
					height: 250,
					url: 'https://i.ibb.co/DQb8WVj/cflr.jpg',
				});
				return imageRet;
			}
			const imgElements = doc.getElementsByTagName('img');
			for (const imgElement of imgElements) {
				if (imgElement.src.includes('yggtorrent') || imgElement.src.startsWith('data:image/png;base64')) {
					continue;
				}
				const image = await fetchImageSize(imgElement.src);
				if (image.width > 250 && image.height > 250) {
					imageRet.push(image);
					break;
				}
			}
		} catch (error) {
			console.error('Error fetching images:', error);
		}
		return imageRet;
	}

	function displayImageHandler() {
		createImageModal();
		let timeout = null;
		let canDisplay = false;
		const torrents = document.querySelectorAll(SELECTORS.RESULTS_TABLE_ROW);
		if (!torrents) return;
		torrents.forEach((torrent) => {
			const torrentNameLink = torrent.querySelector(SELECTORS.TORRENT_NAME_LINK);
			if (!torrentNameLink) return;

			torrentNameLink.addEventListener('mouseenter', async (e) => {
				timeout = setTimeout(async () => {
					if (e.target.id !== 'torrent_name') return;
					canDisplay = true;
					const images = await getImages(e.target.href);
					if (canDisplay) {
						displayImageModal(e, images[0]);
					}
				}, CONSTANTS.MOUSEENTER_DELAY);
			});

			torrentNameLink.addEventListener('mousemove', (e) => {
				const modal = document.getElementById('imageModal');
				if (modal) {
					const mouseY = e.clientY - 25;
					const outOfScreen =
						mouseY + document.getElementById('imageModalImage').offsetHeight - window.innerHeight;
					modal.style.top =
						outOfScreen > -25 ? mouseY - outOfScreen - 25 + 'px' : mouseY + 'px';
					modal.style.left = e.clientX + 125 + 'px';
				}
			});

			torrentNameLink.addEventListener('mouseout', () => {
				document.getElementById('imageModal').style.display = 'none';
				canDisplay = false;
				clearTimeout(timeout);
			});
		});
	}

	function createImageModal() {
		const modal = document.createElement('div');
		modal.id = 'imageModal';
		modal.classList.add('modal');
		modal.style.display = 'none';

		const modalImage = document.createElement('img');
		modalImage.id = 'imageModalImage';
		modalImage.classList.add('modal-content');
		modalImage.style = CONSTANTS.IMAGE_MODAL_STYLE;

		modal.appendChild(modalImage);
		document.body.append(modal);
	}

	function displayImageModal(event, image) {
		const modal = document.getElementById('imageModal');
		if (modal) {
			const mouseY = event.clientY - 25;
			const modalImage = document.getElementById('imageModalImage');
			modalImage.src = image.url;
			modal.style.left = event.clientX + 125 + 'px';
			modal.style.display = 'block';
			const outOfScreen =
				mouseY + modalImage.offsetHeight - window.innerHeight;
			modal.style.top =
				outOfScreen > -25 ? mouseY - outOfScreen - 25 + 'px' : mouseY + 'px';
		}
	} */

	function addDownloadButtonToTorrents() {
		const torrents = document.querySelectorAll(SELECTORS.RESULTS_TABLE_ROW);
		torrents.forEach((torrent) => {
			const torrentId = torrent.querySelector('a[target]')?.target;
			if (!torrentId) return;

			const downloadIcon = document.createElement('span');
			downloadIcon.classList.add('ico_download');
			downloadIcon.classList.add('custom_ygg');

			const downloadButton = document.createElement('a');
			downloadButton.href = `/engine/download_torrent?id=${torrentId}`;
			downloadButton.append(downloadIcon);
			downloadButton.style = 'float: left; color: rgb(98, 219, 168)';

			const nameLink = torrent.querySelector('td:nth-child(3) a');
			if (nameLink) {
				nameLink.parentNode.insertBefore(downloadButton, nameLink);
			}
		});
	}

	function hideSidebar() {
		const sidebar = document.getElementById('cat');
		if (sidebar && sidebar.classList.contains('active')) {
			sidebar.querySelector('.open').click();
		}
	}

	function displayLargerNfo() {
		const modal = document.getElementById(SELECTORS.NFO_MODAL);
		if (!modal) return;

		const modalDialog = modal.querySelector('.modal-dialog');
		modalDialog.classList.remove('modal-sm');
		modalDialog.classList.add('modal-lg');
	}

	function searchByLatestFirst() {
		const searchForm = document.querySelector(SELECTORS.SEARCH_FORM);
		if (!searchForm) return;

		const orderInput = document.createElement('input');
		orderInput.name = 'order';
		orderInput.value = 'desc';
		orderInput.style = 'display: none';

		const sortInput = document.createElement('input');
		sortInput.name = 'sort';
		sortInput.value = 'publish_date';
		sortInput.style = 'display: none';

		searchForm.append(orderInput);
		searchForm.append(sortInput);
	}

	function keepSearchWhenClickingOnSubcategoryIcon() {
		document.querySelectorAll('[class^="tag_subcat_"]').forEach((node) => {
			const subcategoryId = node.className.split('tag_subcat_')[1];
			node.parentNode.href = `${document.URL}&sub_category=${subcategoryId}`;
		});
	}

	function betterDarkTheme() {
		const customStyles = `
			.custom_ygg{vertical-align:middle}.promo-container{display:none!important;}#over-18-notification,.misc,.donate.pulse{display:none}#middle .row .results tr:nth-child(odd) td{background:#2a313ce8;color:#cbd1da}#middle .row .results tr td:nth-child(8){color:#4caf50}#middle .row .results tr td:nth-child(9){color:#f44336}#middle .row .results td .ico_comment,#middle .row .results td{background-color:#2c343f;border:solid 1px #1b1e24;color:#cbd1da}#middle .row table td a{color:#cbd1da}.results thead th{background:#354150;color:#cbd1da}#middle .row .results tr:hover td{background:hsla(155,43%,25%,1)}#middle .row .search-criteria{background:#354150}#middle .row .search-criteria td.adv_search_option,#middle .row .search-criteria td:first-child{background:#354150;color:#cbd1da!important}#middle .row .search-criteria td{background:#354150;color:#cbd1da;border-right:1px solid #1b1e24;border-bottom:1px solid #1b1e24}#middle .search-criteria td input{background:#2a313c;color:#6c798d}#middle .search-criteria td button.solo{transition:.1s ease-in-out;background:transparent;max-width:100%;color:#5ad9a4;top:-1px;font-size:11px;font-weight:700;text-transform:uppercase;border:3px solid #5ad9a4;border-radius:25px;padding:5px 10px}#middle .search-criteria td button.solo:hover{color:#fff;background:#5ad9a4;text-decoration:none}.form-control,.select2-selection__rendered,.select2-selection__rendered{background:#2a313c;border:1px solid #1b1e24}.select2-container--bootstrap .select2-selection--single{background-color:#2a313c}.select2-container--bootstrap .select2-selection--single .select2-selection__rendered{color:#6c798d}.select2-dropdown{background-color:#2a313c;color:#6c798d}.select2-container--bootstrap .select2-dropdown{border:1px solid #1b1e24}.select2-container--bootstrap .select2-search--dropdown .select2-search__field{border:1px solid #1b1e24;background-color:#2a313c;color:#6c798d}.select2-container--bootstrap .select2-results__option[aria-selected=true]{background-color:#354150}.select2-container--bootstrap .select2-selection{background-color:#2a313c;border:1px solid #1b1e24!important}.select2-container--bootstrap .select2-selection .select2-selection__rendered{border:none}.select2-container,.select2-container--bootstrap{width:400px!important}input:focus{border-color:#6c798d!important;color:#cbd1da}#middle .pagination{background:#2a313c;color:#cbd1da}#middle .pagination li{border-left:1px solid #1b1e24}#middle .pagination li a{background:#2a313c;color:#cbd1da}#middle .pagination li a:hover{background:#6c798d}#middle .row table.infos-torrent td.adv_search_option,#middle .row table.infos-torrent td:first-child{background:#354150;color:#cbd1da}#middle .row table.infos-torrent td{background:#354150;color:#cbd1da;border-right:1px solid #1b1e24;border-bottom:1px solid #1b1e24}.description-header{background:#354150;border-bottom:1px solid #1b1e24}#middle table td .red{color:#ef5f5f}#middle .default{background:#354150!important;color:#cbd1da}#middle .default font{color:#cbd1da}#middle .default a{color:#5ad9a4}#nfoModal .modal-sm{max-width:60%!important}#nfoModal .modal-body{background-color:#354150!important;color:#cbd1da}#nfoModal .modal-header{border-color:rgba(0,0,0,.125)}#nfoModal .modal-footer{background-color:#354150!important;border-color:rgba(0,0,0,.125)}#commentary{background:#354150}#middle .comment h4,#middle #commentary h4{color:#cbd1da}#middle .add-comment,#middle .add-note{background:#354150;border-bottom:3px solid #6c798d}#commentary li{border-top:1px solid #6c798d}#commentary li .message{background:#6c798d;border:1px solid #6c798d}#commentary li .message:before{border-right:15px solid #6c798d}#commentary li .message:after{border-right:15px solid #6c798d}#commentary li .message .add{color:#cbd1da}#commentary li .message a{color:#fff}#commentary li .left{background:#6c798d;border:1px solid #1b1e24}#comment-list li img[src$="/assets/img/avatar.jpg"]{filter:invert(70%)}#comment-list li .ratio .red{color:#9c0b0b}.wysibb{background:#354150;border:1px solid #1b1e24}.wysibb .wysibb-toolbar .wysibb-toolbar-container .wysibb-toolbar-btn .fonticon{color:#6c798d;text-shadow:none}.wysibb .wysibb-toolbar{border-bottom:1px solid #1b1e24}.wysibb .wysibb-toolbar .wysibb-toolbar-container{border-right:1px solid #1b1e24}.wysibb-toolbar-btn{color:#6c798d}.wysibb-body{color:#fff}.bottom-resize-line:hover,.bottom-resize-line.drag{background:#6c798d}#middle .row table td .input-table{background:#2a313c;color:#cbd1da;border:1px solid #1b1e24;border-radius:5px}#connect{background:#2c343f}#connect h3{color:#cbd1da}#connect input{background:#2a313c;color:#6c798d;border-top:1px solid #1b1e24}#connect input:focus{color:#cbd1da}#connect a{color:#6c798d}#connect a:hover{color:#cbd1da}.form-control:focus{background:#2a313c;color:#cbd1da;border-color:#6c798d!important}.form-control,.select2-selection__rendered,.select2-selection__rendered{color:#6c798d}.field-label-responsive label{color:#6c798d}#middle .row table.detail-account{border-left:2px solid #6c798d}#middle .row table td.adv_search_option,#middle .row table td:first-child{color:#cbd1da} .card{background:#354150}.card-footer{border-top:1px solid rgba(27,30,36,.4)!important;background:#354150}#top_panel img[src$="/assets/img/avatar.jpg"]{filter:invert(70%);border-color:rgba(0,0,0,.125)}.table-bordered{border:solid 1px #1b1e24}.inbox thead th{background:#354150;color:#cbd1da}.inbox thead td{border:solid 1px #1b1e24}#middle section.content div.row div.card img[src$="/assets/img/avatar.jpg"]{filter:invert(70%)} .well{background-color:#343a40;border-color:rgba(0,0,0,.125)}.well[style^="background:#fff"]{background-color:#6c757d!important;border-color:rgba(0,0,0,.125)}.well[style^="background:#e0ffd7"]{background-color:#48a648!important}.well[style^="background:#f0f0f0"]{text-decoration:line-through;background-color:#555!important;border-color:rgba(0,0,0,.125)}.well strong[style^="color:#3b454e"]{color:#cbd1da!important}[role=button],a,area,button,input,label,select,summary,textarea{touch-action:auto}#middle .default .date,#middle #description .date{background:#2c343f;border-top:1px solid rgba(27,30,36,.4)}#middle .row .results td{background-color:#2c343f;border:solid 1px #1b1e24;color:#cbd1da}#middle .row table td{background:#354150;color:#cbd1da;border-right:1px solid #1b1e24;border-bottom:1px solid #1b1e24}#middle .row .results tr:nth-child(odd) td{background:#232a33}.results thead th{background:#354150;color:#cbd1da}::-webkit-scrollbar{background-color:#202324;color:#aba499}::-webkit-scrollbar-thumb{background-color:#454a4d}::-webkit-scrollbar-thumb:hover{background-color:#575e62}::-webkit-scrollbar-thumb:active{background-color:#484e51}::-webkit-scrollbar-corner{background-color:#181a1b}#middle .row .results tr:hover td{background:hsla(155,43%,25%,1)}.results{background:#232a33}#panel-btn strong{background-image:url(https://i.ibb.co/sw65szs/blue-rank.gif);color:#009CD6;font-weight:bold;text-shadow:#009CD6 2px 0 6px;}
		`;
		GM_addStyle(customStyles);
	}
})();