// ==UserScript== // @name Torrent Quick Search // @namespace https://github.com/TMD20/torrent-quick-search // @supportURL https://github.com/TMD20/torrent-quick-search // @version 1.2.9 // @description Toggle for Searching Torrents via Search aggegrator // @icon https://cdn2.iconfinder.com/data/icons/flat-icons-19/512/Eye.png // @author tmd // @noframes // @inject-into page // @run-at document-end // @require https://openuserjs.org/src/libs/sizzle/GM_config.min.js // @grant GM_getValue // @grant GM_setValue // @grant GM.xmlhttpRequest // @grant GM.registerMenuCommand // @grant GM.notification // @match https://animebytes.tv/requests.php?action=viewrequest&id=* // @match https://animebytes.tv/series.php?id=* // @match https://animebytes.tv/torrents.php?id=* // @match https://blutopia.xyz/requests/* // @match https://blutopia.xyz/torrents/* // @match https://beyond-hd.me/requests/* // @match https://beyond-hd.me/torrents/* // @match https://imdb.com/title/* // @match https://www.imdb.com/title/* // @match https://www.themoviedb.org/movie/* // @match https://www.themoviedb.org/tv/* // @license MIT // @downloadURL none // ==/UserScript== ` General Functions Functions that don't fit in any other catergory ` async function toggleSearch(e){ content=document.querySelector("#searchcontent") if (content.style.visibility === "visible") { content.style.pointerEvents="none" document.querySelector("#toggle").style.height='2%' document.querySelector("#toggle").style.width='2%' content.style.visibility = "hidden"; } else { content.style.pointerEvents="all" document.querySelector("#toggle").style.height='5%' document.querySelector("#toggle").style.width='5%' content.style.visibility = "visible"; try{ await searchObj.setup() } catch(error) { GM.notification(error.toString(), program,searchIcon) document.querySelector("#toggle").style.height='2%' document.querySelector("#toggle").style.width='2%' document.querySelector("#searchcontent").style.visibility = "hidden"; throw new Error(error); } } } searchObj={ async doSearch(){ document.querySelector("#msgnode").textContent="Loading" reqs=[] resetResultList() indexers=await getIndexers() getTableHead() document.querySelector("#msgnode").textContent="Fetching Results From Indexers" imdb=await getIMDB() //reset count let count=[] data=await Promise.allSettled(indexers.map((e)=>searchIndexer(e,imdb,indexers.length,count))); errorMsgs=data.filter((e)=>e["status"]=="rejected").map((e)=>e["reason"]) errorMsgs= [...new Set(errorMsgs)] if(errorMsgs.length>0){ throw new Error(errorMsgs.join("\n")) } addNumbers() console.log("Finished Fetching") document.querySelector("#msgnode").textContent="Finished" }, cancel(){ clearTimeout(this.timeoutID) }, setup(){ if (typeof this.timeoutID === 'number') { this.cancel(); } this.timeoutID = setTimeout(this.doSearch(), 1000); }, } async function searchIndexer(indexerObj,imdb,total,count){ searchprogram=GM_config.get('searchprogram') let data=null if (searchprogram=="Prowlarr"){ data=await searchProwlarrIndexer(indexerObj) } else if(searchprogram=="Jackett"){ data=await searchJackettIndexer(indexerObj) } else if(searchprogram=="NZBHydra2"){ data=await searchHydra2Indexer(indexerObj) } data=data.filter((e)=>imdbFilter(e,imdb)) data=data.filter((e)=>currSiteFilter(e["infoUrl"])) processResults(data) count.push(indexerObj["id"]) msg=`Fetching Results From Indexers:${count.length}/${total}` document.querySelector("#msgnode").textContent=msg console.log(msg) } async function searchProwlarrIndexer(indexer){ req=await fetch(getSearchURLProwlarr(indexer["id"])) data=JSON.parse(req.responseText) data.forEach((e)=>{ if(e["indexerFlags"].includes("freeleech")){ e["cost"]="Freeleech" } else{ e["cost"]="Cost Unknown With Prowlarr" } }) return data } async function searchJackettIndexer(indexer){ req=await fetch(getSearchURLJackett(indexer["id"])) data=JSON.parse(req.responseText)["Results"] console.log(`${indexer["name"]}:${data}`) return data.map((e)=>{ return {"title":e["Title"], "indexer":e["Tracker"], "grabs":e["Grabs"], "publishDate":e["PublishDate"], "size":e["Size"], "leechers":e["Peers"], "seeders":e["Seeders"], "infoUrl":e["Details"], "downloadUrl":e["Link"], "imdbId":e["Imdb"], "cost":`${(1-e["DownloadVolumeFactor"])*100}% Freeleech` } }) } async function searchHydra2Indexer(indexer){ req=await fetch(getSearchURLHydraTor(indexer["id"])) req2=await fetch(getSearchURLHydraNZB(indexer["id"])) parser = new DOMParser(); data=[...Array.from(parser.parseFromString(req.responseText,"text/xml").querySelectorAll("channel>item")),...Array.from(parser.parseFromString(req2.responseText,"text/xml").querySelectorAll("channel>item"))] console.log(`${indexer["name"]}:${data}`) console.log(req.responseText) console.log(req.finalUrl) return data.map((e)=>{ t=[["title","title","textContent"],["indexer","[name=hydraIndexerName]","null"],["leechers","[name=peers]","null"],["seeders","[name=seeders]","null"],["cost","[name=downloadvolumefactor]","null"], ["publishDate","pubDate","textContent"],["size","size","textContent"],["infoUrl","comments","textContent"],["downloadUrl","links","textContent"],["imdbId"],"[name=imdb]","null"] out={} out["grabs"]=null for(i in t){ key=t[i][0] node=e.querySelector(t[i][1]) textContent=(t[i][2]=="textContent") if(!node){ continue } if(textContent){ out[key]=node.textContent } else{ out[key]=node.getAttribute("value") } } return out }) } function fetch(url){ if(url.match(/htt(p|ps):\/\//)==null){ url=`"http://${url}"` } return new Promise((resolve, reject) => { GM.xmlhttpRequest( { 'method' : 'GET', 'url' : url, onload : response => { resolve(response) }, onerror : response => { reject(response.responseText) }, } ) })} function getParser(){ siteName=standardNames[window.location.host] || window.location.host data=infoParser[siteName] if (data===undefined){ msg="Could not get Parser" GM.notification(msg, program,searchIcon) throw new Error(msg); } return data } function verifyConfig(){ if (GM_config.get('searchapi',"null")=="null"||GM_config.get('searchurl',"null")=="null"){ return false } if (GM_config.get('searchapi',"null")==""||GM_config.get('searchurl',"null")==""){ return false } return true } ` DOM Manipulators These Functions are used to manipulate the DOM ` function getTableHead(){ resultList=document.querySelector("#resultlist") node=document.querySelector("#resulthead"); node.innerHTML=`