// ==UserScript== // @name Torrent Quick Search // @namespace https://github.com/TMD20/torrent-quick-search // @supportURL https://github.com/TMD20/torrent-quick-search // @version 1.31 // @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://beyond-hd.me/library/title/* // @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("#torrent-quicksearch-box") if (content.style.display === "inline-block") { content.style.pointerEvents="none" document.querySelector("#torrent-quicksearch-toggle").style.height='2%' document.querySelector("#torrent-quicksearch-toggle").style.width='2%' document.querySelector("#torrent-quicksearch-toggle").style.marginBottom='-2%' content.style.display = "none"; } else { document.querySelector("#torrent-quicksearch-msgnode").style.display="block" content.style.pointerEvents="all" document.querySelector("#torrent-quicksearch-toggle").style.height='5%' document.querySelector("#torrent-quicksearch-toggle").style.width='5%' document.querySelector("#torrent-quicksearch-toggle").style.marginBottom='-5%' customSearch=false content.style.display = "inline-block"; try{ obj=searchObj obj.setup() } catch(error) { GM.notification(error.message, program,searchIcon) obj=searchObj obj.cancel() } } } customSearch=false searchObj={ async doSearch(){ document.querySelector("#torrent-quicksearch-msgnode").textContent="Loading" reqs=[] resetResultList() indexers=await getIndexers() imdb=null getTableHead() if(customSearch==false){ document.querySelector("#torrent-quicksearch-customsearch").value=getTitle() } document.querySelector("#torrent-quicksearch-msgnode").textContent="Fetching Results From Indexers" //Get Old IMDB if( document.querySelector("#torrent-quicksearch-imdbinfo").textContent!=imdbParserFail && document.querySelector("#torrent-quicksearch-imdbinfo").textContent.length!=0&& document.querySelector("#torrent-quicksearch-imdbinfo").textContent!="None" ) { imdb=document.querySelector("#torrent-quicksearch-imdbinfo").textContent } //Retrive New IMDB else{ imdb=await getIMDB() document.querySelector("#torrent-quicksearch-imdbinfo").textContent=imdb || imdbParserFail } //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"].message) errorMsgs= [...new Set(errorMsgs)] if(errorMsgs.length>0){ throw new Error(errorMsgs.join("\n")) } addNumbers() console.log("Finished Fetching") document.querySelector("#torrent-quicksearch-msgnode").textContent="Finished" setTimeout(()=> document.querySelector("#torrent-quicksearch-msgnode").style.display="none",3000) }, cancel(){ clearTimeout(this.timeoutID) }, setup(){ if (typeof this.timeoutID === 'number') { this.cancel(); } this.timeoutID = setTimeout(async ()=>{ try{ await this.doSearch() } catch(error){ GM.notification(error.message, program,searchIcon) document.querySelector("#torrent-quicksearch-toggle").style.height='2%' document.querySelector("#torrent-quicksearch-toggle").style.width='2%' document.querySelector("#torrent-quicksearch-toggle").style.marginBottom='-2%' document.querySelector("#torrent-quicksearch-box").style.display = "none"; } }, 1000); }, } async function searchIndexer(indexerObj,imdb,total,count){ msg=null try{ searchprograms=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) } msg=`Results fetched fom ${indexerObj["name"]}:${count.length+1}/${total} Indexers completed` data=data.filter((e)=>imdbFilter(e, imdbCleanup(imdb))) data.forEach((e)=>{ if(e["imdbId"]==0||e["imdbId"]==null){ e["imdbId"]="Not Provided" } }) data=data.filter((e)=>currSiteFilter(e["infoUrl"])) addResultsTable(data) count.push(indexerObj["id"]) document.querySelector("#torrent-quicksearch-msgnode").textContent=msg console.log(msg) } catch(error){ count.push(indexerObj["id"]) document.querySelector("#torrent-quicksearch-msgnode").textContent=msg console.log(msg) console.error(error.message) throw new Error(error.message) } } 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"]="100% 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","link","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 if(key=="cost"){ out[key]=`${(1-node.getAttribute("value"))*100}% Freeleech` } else{ out[key]=node.getAttribute("value") } } return out }) } function fetch(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(){ node=document.querySelector("#torrent-quicksearch-resultheader"); node.innerHTML=` Links Number Title Indexer Grabs Seeders Leechers DLCost Date Size IMDB ` Array.from(node.children).forEach((e,i)=>{ e.style.gridColumnStart=i+1 e.style.fontSize=`${GM_config.get("fontsize",12)}px` }) } function addResultsTable(data){ if (data.length==0){ return } data.forEach((e,i)=>{ resultList=document.querySelector("#torrent-quicksearch-resultlist") node=document.createElement("span"); node.setAttribute("class","torrent-quicksearch-resultitem") node.innerHTML=` Download
Details
? ${e['title']} ${e['indexer']} ${e['grabs']} ${e['seeders']} ${e['leechers']} ${e['cost']} ${new Date(e['publishDate']).toLocaleString("en-CA")} ${(parseInt(e['size'])/1073741824).toFixed(2)} GB ${e['imdbId']} ` Array.from(node.children).forEach((e,i)=>{ e.style.gridColumnStart=i+1 e.style.fontSize=`${GM_config.get("fontsize",12)}px` }) }) resultList.appendChild(node) } function resetResultList(){ document.querySelector("#torrent-quicksearch-resultheader").textContent="" document.querySelector("#torrent-quicksearch-msgnode").textContent="" document.querySelector("#torrent-quicksearch-resultlist").textContent="" } function addNumbers(){ Array.from(document.querySelectorAll(".torrent-quicksearch-resultitem")).slice(1).forEach((e,i)=>{ e.children[1].textContent=`${i}` } ) } function createMainDOM(){ const box = document.createElement("div"); box.setAttribute("id", "torrent-quicksearch-overlay"); rowSplit=12 contentWidth=70 boxMinHeight=5 boxMaxHeight=100 boxHeight=40 boxWidth=70 boxMaxWidth=150 box.innerHTML=`
None