// ==UserScript== // @name copyTorrentToRelated // @namespace https://avistaz.to/profile/dryeyes // @description Copy current torrent row to Related Torrents section // @match https://cinemaz.to/torrent/* // @match https://avistaz.to/torrent/* // @version 0.9.1 // @grant none // @locale English (en) // @downloadURL none // ==/UserScript== 'use strict'; (function(){ function injectFunc(fn) { var scriptElm = document.createElement('script'); scriptElm.setAttribute("type", "application/javascript"); scriptElm.textContent = '(' + fn + ')();'; //scriptElm.async = false; didn't help. document.body.appendChild(scriptElm); // run the script document.body.removeChild(scriptElm); // clean up } function getNoRelatedTorrentsNode () { var noTorrentsFoundNode = document.evaluate('//div[@id="collapseRelatedTorrents"]/div[@class="related-torrents"]/p[normalize-space()="No torrents found!"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; return noTorrentsFoundNode; } function getTableDataNode(tableCaption) { var xpathexp = `//tr/td[strong[contains(text(),'${tableCaption}')]]/following-sibling::td`; var tableDataNode = document.evaluate(xpathexp, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; return tableDataNode; } var cleanedUrl = window.location.href.replace(/(\#.*)$/, ''); var newTR; // the copied element from related torrents query. var nRelated; // # of Related Torrents (including current) var atLeast; // "+" if more than one page of torrents otherwise "" function addExtraInfo() { if (newTR === null) return; var vidResolutionNode = getTableDataNode('Video Resolution'); if (vidResolutionNode !== null) { var vidRes = vidResolutionNode.innerText.trim().toLowerCase(); console.log("Video Resolution:", vidRes); if (vidRes !== 'unknown') { var vidResSpan = document.createElement('span'); vidResSpan.innerHTML = `${vidRes}`; var tfileDiv = newTR.querySelector('td:nth-of-type(2) > div > div:nth-of-type(2)'); if (tfileDiv !== null) { console.log("Adding vidResSpan:", vidResSpan); tfileDiv.appendChild(vidResSpan); } } } var tFileDivNode = newTR.querySelector('div.torrent-file'); var descriptionNode = getTableDataNode('Description'); var descriptionLength = "0"; if (descriptionNode !== null && descriptionNode.innerText.length !== 0) { descriptionLength = (descriptionNode.innerText.length / 1024.0).toFixed(1); } var descriptionSpan = document.createElement('span'); descriptionSpan.innerHTML = ` ${descriptionLength}K`; tFileDivNode.appendChild(descriptionSpan); var screenShotsSmallNode = document.evaluate('//div[@data-target="#collapseScreens"]/small', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; if (screenShotsSmallNode !== null) { console.log("Screens:", screenShotsSmallNode); var nScreens = screenShotsSmallNode.innerText.match(/(\d+)\s+image?/i)[1]; var screenSpan = document.createElement('span'); //screenSpan.innerHTML = ` ${nScreens}`; screenSpan.innerHTML = ` ${nScreens}`; // var aNode = screenSpan.querySelector('a'); // aNode.addEventListener('click', function(){ // var screenshotsHeader = screenShotsSmallNode.parentNode; // screenshotsHeader.scrollIntoView(true); // console.log("ScrollIntoView:", screenshotsHeader); // }, false); tFileDivNode.appendChild(screenSpan); var comments = document.querySelectorAll('div#commentsBlock div.comments > ul li'); console.log("Comments:", comments); var commentsSpan = document.createElement('span'); commentsSpan.innerHTML = ` ${comments.length}`; tFileDivNode.appendChild(commentsSpan); } var tagsNode = getTableDataNode('Tags'); if (tagsNode !== null) { var tagsDiv = document.createElement('div'); var arefs = tagsNode.querySelectorAll('a'); arefs.forEach(function(item) { var tagSpan = document.createElement('span'); tagSpan.innerHTML = ` ${item.innerText}`; tagsDiv.appendChild(tagSpan); }); tFileDivNode.appendChild(tagsDiv); } } function onMainTorrentLoaded () { var i; console.log("XMLHttpRequest loaded."); var relatedRow = this.response; console.log(relatedRow); var relatedRows = relatedRow.querySelectorAll("div.table-responsive tbody > tr"); console.log("Main page torrent rows:", relatedRows); console.log("Looking for:", cleanedUrl); for (i = 0; i < relatedRows.length; i++) { var row = relatedRows[i]; var anode = row.querySelector("a.torrent-filename"); if (anode !== null) { console.log("Anode:", anode); if (anode.href === cleanedUrl) { newTR = row.cloneNode(true); var tdNode = newTR.querySelector("td:last-of-type"); var inode = relatedRow.createElement("i"); inode.innerHTML = ``; tdNode.appendChild(inode); console.log("ClonedTR:", newTR); break; } } } var lastPageLI = document.querySelector("ul.pagination li:nth-last-of-type(2)"); if (lastPageLI !== null) { var nFullPages = Number(lastPageLI.innerText) - 1; nRelated = (relatedRows.length*nFullPages); atLeast = "+"; } else { nRelated = relatedRows.length; atLeast = ""; } addExtraInfo(); } // Download & copy matching torrent row from related torrents url function copyRelatedRow() { var mainURL = document.querySelector("h3.movie-title > a").href; var pieces = mainURL.split("/"); var site = pieces[2]; var torrentID = pieces[4].split("-")[0]; var relatedURL = `https://${site}/movies/torrents/${torrentID}?quality=all`; var xhr = new XMLHttpRequest(); xhr.onload = onMainTorrentLoaded; xhr.open("GET", relatedURL); xhr.responseType = "document"; xhr.send(); console.log("XMLHttpRequest for "+relatedURL+ " sent."); } var relatedAdded = false; function relatedShown () { if (relatedAdded) return; else relatedAdded = true; console.log("Related shown.", document.readyState); var relatedTorrent = document.querySelector("#collapseRelatedTorrents > div.related-torrents > div > table > tbody > tr"); console.log("Related torrent:", relatedTorrent); var noRelatedTorrentsNode = getNoRelatedTorrentsNode(); if (noRelatedTorrentsNode !== null) console.log("After expanded: No related torrents message found."); if (relatedTorrent !== null) { if (newTR !== undefined) { console.log("NewTR:"); console.log(newTR); relatedTorrent.parentNode.insertBefore(newTR, relatedTorrent); } } else { if (noRelatedTorrentsNode !== null) { var divElm = document.createElement('div'); divElm.innerHTML = ` `; console.log("About to create new related."); var tbody = divElm.querySelector("tbody"); if (newTR !== undefined) { console.log("NewTR:"); console.log(newTR); tbody.appendChild(newTR); } var grandParent = noRelatedTorrentsNode.parentNode.parentNode; grandParent.replaceChild(divElm, noRelatedTorrentsNode.parentNode); } else { console.log("Ooops. No related torrents AND couldn't find the No Related Torrents message?", document.readyState); window.alert("Ooops. No related torrents AND couldn't find the No Related Torrents message?\n\nKeep refreshing page until this alert doesn't appear."); } } var relatedTorrents = document.querySelectorAll("#collapseRelatedTorrents > div.related-torrents > div > table > tbody > tr"); console.log("relatedTorrents:", relatedTorrents); var relatedTorrentsA = document.querySelector('div.panel-heading > strong > a'); if (relatedTorrentsA !== null) { if (nRelated === null) { var nTorrents = relatedTorrents.length > 0 ? relatedTorrents.length : 1; relatedTorrentsA.innerText += " [" + nTorrents + "]"; } else { relatedTorrentsA.innerText += " [" + nRelated + atLeast + "]"; } } } // Expose relatedShown() to injected func. window.relatedShown = relatedShown; // doesn't work with Greasemonkey 4.1 //exportFunction(relatedShown, window, {defineAs: "relatedShown"}); // doesn't work in Greasemonkey 3.17, get exportFunction not defined error :( // Use script injection so can use jQuery to listen to shown.bs.collapse event which // will be automatically triggered when we click the Related Torrents panel during // load event processing. function injectedFunc() { console.log("Injected function running"); var relatedTorrentsDiv = document.querySelector('div#collapseRelatedTorrents'); console.log ("relatedTorrentsDiv:", relatedTorrentsDiv); $(relatedTorrentsDiv).on('shown.bs.collapse', relatedShown); // also works! } function clickRelated() { console.log("Click Related Torrents header."); var relatedTorrentsA = document.querySelector('div.panel-heading > strong > a'); if (relatedTorrentsA !== null) { relatedTorrentsA.click(); } } function markTableRow(dataName, dataID) { var dataNode = getTableDataNode(dataName); if (dataNode !== null) { dataNode.parentNode.id = dataID; } } function onLoadHandler() { console.log("Load event occurred."); markTableRow('Video Quality', "video-quality-row"); markTableRow('Description', "description-row"); var panelNode = document.evaluate('//div[@data-target="#collapseScreens"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; panelNode.id = "screenshots-panel"; panelNode = document.evaluate('//div[@data-target="#collapseComments"]', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; panelNode.id = "comments-panel"; markTableRow('Thanked', 'thanked-row'); markTableRow('Subtitles', 'subtitles-row'); if (newTR !== undefined) { clickRelated(); } else { console.log("XMLHttpRequest not done. Wait 2 seconds to click."); setTimeout(clickRelated, 2000); } } console.log("UserScript running"); copyRelatedRow(); injectFunc(injectedFunc); window.addEventListener('load', onLoadHandler, false); })();