Kfunga/mirror
0
1from aria2p import (2 API as ariaAPI,3 Client as ariaClient4)5from flask import (6 Flask,7 request8)9from logging import (10 getLogger,11 FileHandler,12 StreamHandler,13 INFO,14 basicConfig15)16from qbittorrentapi import (17 NotFound404Error,18 Client as QbClient19)20from time import sleep21from sabnzbdapi import SabnzbdClient22from asyncio import (23 get_running_loop,24 new_event_loop,25 set_event_loop26)27 28from web.nodes import make_tree29 30app = Flask(__name__)31 32try:33 web_loop = get_running_loop()34except RuntimeError:35 web_loop = new_event_loop()36 set_event_loop(web_loop)37 38qbittorrent_client = QbClient(39 host="localhost",40 port=8090,41 VERIFY_WEBUI_CERTIFICATE=False,42 REQUESTS_ARGS={"timeout": (43 30,44 6045 )},46 HTTPADAPTER_ARGS={47 "pool_maxsize": 200,48 "pool_block": True49 },50)51 52sabnzbd_client = SabnzbdClient(53 host="http://localhost",54 api_key="zee",55 port="8070",56)57 58aria2 = ariaAPI(59 ariaClient(60 host="http://localhost",61 port=6800,62 secret=""63 )64)65 66basicConfig(67 format="%(levelname)s | From %(name)s -> %(module)s line no: %(lineno)d | %(message)s",68 handlers=[69 FileHandler("Zee_Logs.txt"),70 StreamHandler()71 ],72 level=INFO,73)74 75LOGGER = getLogger(__name__)76 77page = """78<html lang="en">79 <head>80 <meta charset="UTF-8" />81 <meta http-equiv="X-UA-Compatible" content="IE=edge" />82 <meta name="viewport" content="width=device-width, initial-scale=1.0" />83 <title>Torrent File Selector</title>84 <link rel="icon" href="https://telegra.ph/file/43af672249c94053356c7.jpg" type="image/jpg">85 <script86 src="https://code.jquery.com/jquery-3.5.1.slim.min.js"87 integrity="sha256-4+XzXVhsDmqanXGHaHvgh1gMQKX40OUvDEBTu8JcmNs="88 crossorigin="anonymous"89 ></script>90 <link rel="preconnect" href="https://fonts.googleapis.com" />91 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />92 <link93 href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"94 rel="stylesheet"95 />96 <link97 rel="stylesheet"98 href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"99 integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p"100 crossorigin="anonymous"101 />102<style>103 104*{105 margin: 0;106 padding: 0;107 box-sizing: border-box;108 font-family: "Ubuntu", sans-serif;109 list-style: none;110 text-decoration: none;111 outline: none !important;112 color: white;113}114 115body{116 background-color: #0D1117;117}118 119header{120 margin: 3vh 1vw;121 padding: 0.5rem 1rem 0.5rem 1rem;122 display: flex;123 align-items: center;124 justify-content: space-between;125 border-bottom: #161B22;126 border-radius: 30px;127 background-color: #161B22;128 border: 2px solid rgba(255, 255, 255, 0.11);129}130 131header:hover, section:hover{132 box-shadow: 0px 0px 15px black;133}134 135.brand{136 display: flex;137 align-items: center;138}139 140img{141 width: 2.5rem;142 height: 2.5rem;143 border: 2px solid black;144 border-radius: 50%;145}146 147.name{148 margin-left: 1vw;149 font-size: 1.5rem;150}151 152.intro{153 text-align: center;154 margin-bottom: 2vh;155 margin-top: 1vh;156}157 158.social a{159 font-size: 1.5rem;160 padding-left: 1vw;161}162 163.social a:hover, .brand:hover{164 filter: invert(0.3);165}166 167section{168 margin: 0vh 1vw;169 margin-bottom: 10vh;170 padding: 1vh 3vw;171 display: flex;172 flex-direction: column;173 border: 2px solid rgba(255, 255, 255, 0.11);174 border-radius: 20px;175 background-color: #161B22 ;176}177 178li:nth-child(1){179 padding: 1rem 1rem 0.5rem 1rem;180}181 182li:nth-child(n+1){183 padding-left: 1rem;184}185 186li label{187 padding-left: 0.5rem;188}189 190li{191 padding-bottom: 0.5rem;192}193 194span{195 margin-right: 0.5rem;196 cursor: pointer;197 user-select: none;198 transition: transform 200ms ease-out;199}200 201span.active{202 transform: rotate(90deg);203 -ms-transform: rotate(90deg); /* for IE */204 -webkit-transform: rotate(90deg);/* for browsers supporting webkit (such as chrome, firefox, safari etc.). */205 display: inline-block;206}207 208ul{209 margin: 1vh 1vw 1vh 1vw;210 padding: 0 0 0.5rem 0;211 border: 2px solid black;212 border-radius: 20px;213 background-color: #1c2129;214 overflow: hidden;215}216 217input[type="checkbox"]{218 cursor: pointer;219 user-select: none;220}221 222input[type="submit"] {223 border-radius: 20px;224 margin: 2vh auto 1vh auto;225 width: 50%;226 display: block;227 height: 5.5vh;228 border: 2px solid rgba(255, 255, 255, 0.11);229 background-color: #0D1117;230 font-size: 16px;231 font-weight: 500;232}233 234input[type="submit"]:hover, input[type="submit"]:focus{235 background-color: rgba(255, 255, 255, 0.068);236 cursor: pointer;237}238 239@media (max-width: 768px){240 input[type="submit"]{241 width: 100%;242 }243}244 245#treeview .parent {246 position: relative;247}248 249#treeview .parent > ul {250 display: none;251}252 253#sticks {254 margin: 0vh 1vw;255 margin-bottom: 1vh;256 padding: 1vh 3vw;257 display: flex;258 flex-direction: column;259 border: 2px solid rgba(255, 255, 255, 0.11);260 border-radius: 20px;261 background-color: #161b22;262 align-items: center;263}264 265#sticks.stick {266 position: sticky;267 top: 0;268 z-index: 10000;269}270</style>271<script>272function s_validate() {273 if ($("input[name^='filenode_']:checked").length == 0) {274 alert("Select one file at least!");275 return false;276 }277 }278</script>279</head>280<body>281 <!--© Designed and coded by @bipuldey19-Telegram-->282 <header>283 <div class="brand">284 <img285 src="https://telegra.ph/file/43af672249c94053356c7.jpg"286 alt="logo"287 />288 <a href="https://t.me/anas_tayyar">289 <h2 class="name">Bittorrent Selection</h2>290 </a>291 </div>292 <div class="social">293 <a href="https://www.github.com/anasty17/mirror-leech-telegram-bot"><i class="fab fa-github"></i></a>294 <a href="https://t.me/anas_tayyar"><i class="fab fa-telegram"></i></a>295 </div>296 </header>297 <div id="sticks">298 <h4>Selected files: <b id="checked_files">0</b> of <b id="total_files">0</b></h4>299 <h4>Selected files size: <b id="checked_size">0</b> of <b id="total_size">0</b></h4>300 </div>301 <section>302 <form action="{form_url}" onsubmit="return s_validate()" method="POST">303 {My_content}304 <input type="submit" name="Select these files ;)">305 </form>306 </section>307 308 <script>309 $(document).ready(function () {310 docready();311 var tags = $("li").filter(function () {312 return $(this).find("ul").length !== 0;313 });314 315 tags.each(function () {316 $(this).addClass("parent");317 });318 319 $("body").find("ul:first-child").attr("id", "treeview");320 $(".parent").prepend("<span>▶</span>");321 322 $("span").click(function (e) {323 e.stopPropagation();324 e.stopImmediatePropagation();325 $(this).parent( ".parent" ).find(">ul").toggle("slow");326 if ($(this).hasClass("active")) $(this).removeClass("active");327 else $(this).addClass("active");328 });329 });330 331 if(document.getElementsByTagName("ul").length >= 10){332 var labels = document.querySelectorAll("label");333 //Shorting the file/folder names334 labels.forEach(function (label) {335 if (label.innerText.toString().split(" ").length >= 9) {336 let FirstPart = label.innerText337 .toString()338 .split(" ")339 .slice(0, 5)340 .join(" ");341 let SecondPart = label.innerText342 .toString()343 .split(" ")344 .splice(-5)345 .join(" ");346 label.innerText = `${FirstPart}... ${SecondPart}`;347 }348 if (label.innerText.toString().split(".").length >= 9) {349 let first = label.innerText350 .toString()351 .split(".")352 .slice(0, 5)353 .join(" ");354 let second = label.innerText355 .toString()356 .split(".")357 .splice(-5)358 .join(".");359 label.innerText = `${first}... ${second}`;360 }361 });362 }363 </script>364 365<script>366$('input[type="checkbox"]').change(function(e) {367 var checked = $(this).prop("checked"),368 container = $(this).parent(),369 siblings = container.siblings();370/*371 $(this).attr('value', function(index, attr){372 return attr == 'yes' ? 'noo' : 'yes';373 });374*/375 container.find('input[type="checkbox"]').prop({376 indeterminate: false,377 checked: checked378 });379 function checkSiblings(el) {380 var parent = el.parent().parent(),381 all = true;382 el.siblings().each(function() {383 let returnValue = all = ($(this).children('input[type="checkbox"]').prop("checked") === checked);384 return returnValue;385 });386 387 if (all && checked) {388 parent.children('input[type="checkbox"]').prop({389 indeterminate: false,390 checked: checked391 });392 checkSiblings(parent);393 } else if (all && !checked) {394 parent.children('input[type="checkbox"]').prop("checked", checked);395 parent.children('input[type="checkbox"]').prop("indeterminate", (parent.find('input[type="checkbox"]:checked').length > 0));396 checkSiblings(parent);397 } else {398 el.parents("li").children('input[type="checkbox"]').prop({399 indeterminate: true,400 checked: false401 });402 }403 }404 checkSiblings(container);405});406</script>407<script>408 function docready () {409 $("label[for^='filenode_']").css("cursor", "pointer");410 $("label[for^='filenode_']").click(function () {411 $(this).prev().click();412 });413 checked_size();414 checkingfiles();415 var total_files = $("label[for^='filenode_']").length;416 $("#total_files").text(total_files);417 var total_size = 0;418 var ffilenode = $("label[for^='filenode_']");419 ffilenode.each(function () {420 var size = parseFloat($(this).data("size"));421 total_size += size;422 $(this).append(" - " + humanFileSize(size));423 });424 $("#total_size").text(humanFileSize(total_size));425 };426 function checked_size() {427 var checked_size = 0;428 var checkedboxes = $("input[name^='filenode_']:checked");429 checkedboxes.each(function () {430 var size = parseFloat($(this).data("size"));431 checked_size += size;432 });433 $("#checked_size").text(humanFileSize(checked_size));434 }435 function checkingfiles() {436 var checked_files = $("input[name^='filenode_']:checked").length;437 $("#checked_files").text(checked_files);438 }439 $("input[name^='foldernode_']").change(function () {440 checkingfiles();441 checked_size();442 });443 $("input[name^='filenode_']").change(function () {444 checkingfiles();445 checked_size();446 });447 function humanFileSize(size) {448 var i = -1;449 var byteUnits = [' kB', ' MB', ' GB', ' TB', 'PB', 'EB', 'ZB', 'YB'];450 do {451 size = size / 1024;452 i++;453 } while (size > 1024);454 return Math.max(size, 0).toFixed(1) + byteUnits[i];455 }456 function sticking() {457 var window_top = $(window).scrollTop();458 var div_top = $('.brand').offset().top;459 if (window_top > div_top) {460 $('#sticks').addClass('stick');461 } else {462 $('#sticks').removeClass('stick');463 }464 }465 $(function () {466 $(window).scroll(sticking);467 sticking();468 });469</script>470</body>471</html>472"""473 474code_page = """475<html lang="en">476 <head>477 <meta charset="UTF-8" />478 <meta http-equiv="X-UA-Compatible" content="IE=edge" />479 <meta name="viewport" content="width=device-width, initial-scale=1.0" />480 <title>Torrent Code Checker</title>481 <link rel="icon" href="https://telegra.ph/file/43af672249c94053356c7.jpg" type="image/jpg">482 <link rel="preconnect" href="https://fonts.googleapis.com" />483 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />484 <link485 href="https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700&display=swap"486 rel="stylesheet"487 />488 <link489 rel="stylesheet"490 href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css"491 integrity="sha384-AYmEC3Yw5cVb3ZcuHtOA93w35dYTsvhLPVnYs9eStHfGJvOvKxVfELGroGkvsg+p"492 crossorigin="anonymous"493 />494 <style>495 *{496 margin: 0;497 padding: 0;498 box-sizing: border-box;499 font-family: "Ubuntu", sans-serif;500 list-style: none;501 text-decoration: none;502 color: white;503}504 505body{506 background-color: #0D1117;507}508 509header{510 margin: 3vh 1vw;511 padding: 0.5rem 1rem 0.5rem 1rem;512 display: flex;513 align-items: center;514 justify-content: space-between;515 border-bottom: #161B22;516 border-radius: 30px;517 background-color: #161B22;518 border: 2px solid rgba(255, 255, 255, 0.11);519}520 521header:hover, section:hover{522 box-shadow: 0px 0px 15px black;523}524 525.brand{526 display: flex;527 align-items: center;528}529 530img{531 width: 2.5rem;532 height: 2.5rem;533 border: 2px solid black;534 border-radius: 50%;535}536 537.name{538 color: white;539 margin-left: 1vw;540 font-size: 1.5rem;541}542 543.intro{544 text-align: center;545 margin-bottom: 2vh;546 margin-top: 1vh;547}548 549.social a{550 font-size: 1.5rem;551 color: white;552 padding-left: 1vw;553}554 555.social a:hover, .brand:hover{556 filter: invert(0.3);557}558 559section{560 margin: 0vh 1vw;561 margin-bottom: 10vh;562 padding: 1vh 3vw;563 display: flex;564 flex-direction: column;565 border: 2px solid rgba(255, 255, 255, 0.11);566 border-radius: 20px;567 background-color: #161B22 ;568 color: white;569}570 571section form{572 display: flex;573 margin-left: auto;574 margin-right: auto;575 flex-direction: column;576}577 578section div{579 background-color: #0D1117;580 border-radius: 20px;581 max-width: fit-content;582 padding: 0.7rem;583 margin-top: 2vh;584}585 586section label{587 font-size: larger;588 font-weight: 500;589 margin: 0 0 0.5vh 1.5vw;590 display: block;591}592 593section input[type="text"]{594 border-radius: 20px;595 outline: none;596 width: 50vw;597 height: 4vh;598 padding: 1rem;599 margin: 0.5vh;600 border: 2px solid rgba(255, 255, 255, 0.11);601 background-color: #3e475531;602 box-shadow: inset 0px 0px 10px black;603}604 605section input[type="text"]:focus{606 border-color: rgba(255, 255, 255, 0.404);607}608 609section button{610 border-radius: 20px;611 margin-top: 1vh;612 width: 100%;613 height: 5.5vh;614 border: 2px solid rgba(255, 255, 255, 0.11);615 background-color: #0D1117;616 color: white;617 font-size: 16px;618 font-weight: 500;619 cursor: pointer;620 transition: background-color 200ms ease;621}622 623section button:hover, section button:focus{624 background-color: rgba(255, 255, 255, 0.068);625}626 627section span{628 display: block;629 font-size: x-small;630 margin: 1vh;631 font-weight: 100;632 font-style: italic;633 margin-left: 23%;634 margin-right: auto;635 margin-bottom: 2vh;636}637 638@media (max-width: 768px) {639 section form{640 flex-direction: column;641 width: 90vw;642 }643 644 section div{645 max-width: 100%;646 margin-bottom: 1vh;647 }648 649 section label{650 margin-left: 3vw;651 margin-top: 1vh;652 }653 654 section input[type="text"]{655 width: calc(100% - 0.3rem);656 }657 658 section button{659 width: 100%;660 height: 5vh;661 display: block;662 margin-left: auto;663 margin-right: auto;664 }665 666 section span{667 margin-left: 5%;668 }669}670 </style>671 </head>672<body>673 <!--© Designed and coded by @bipuldey19-Telegram-->674 <header>675 <div class="brand">676 <img677 src="https://telegra.ph/file/43af672249c94053356c7.jpg"678 alt="logo"679 />680 <a href="https://t.me/anas_tayyar">681 <h2 class="name">Bittorrent Selection</h2>682 </a>683 </div>684 <div class="social">685 <a href="https://www.github.com/anasty17/mirror-leech-telegram-bot"><i class="fab fa-github"></i></a>686 <a href="https://t.me/anas_tayyar"><i class="fab fa-telegram"></i></a>687 </div>688 </header>689 <section>690 <form action="{form_url}">691 <div>692 <label for="pin_code">Pin Code :</label>693 <input694 type="text"695 name="pin_code"696 placeholder="Enter the code that you have got from Telegram to access the Torrent"697 />698 </div>699 <button type="submit" class="btn btn-primary">Submit</button>700 </form>701 <span702 >* Dont mess around. Your download will get messed up.</703 >704 </section>705</body>706</html>707"""708 709 710def re_verfiy(paused, resumed, hash_id):711 paused = paused.strip()712 resumed = resumed.strip()713 if paused:714 paused = paused.split("|")715 if resumed:716 resumed = resumed.split("|")717 718 k = 0719 while True:720 res = qbittorrent_client.torrents_files(torrent_hash=hash_id)721 verify = True722 for i in res:723 if (724 str(i.id) in paused725 and i.priority != 0726 ):727 verify = False728 break729 if (730 str(i.id) in resumed731 and i.priority == 0732 ):733 verify = False734 break735 if verify:736 break737 LOGGER.info("Reverification Failed! Correcting stuff...")738 sleep(1)739 try:740 qbittorrent_client.torrents_file_priority(741 torrent_hash=hash_id,742 file_ids=paused,743 priority=0744 )745 except NotFound404Error as e:746 raise NotFound404Error from e747 except Exception as e:748 LOGGER.error(f"{e} Errored in reverification paused!")749 try:750 qbittorrent_client.torrents_file_priority(751 torrent_hash=hash_id,752 file_ids=resumed,753 priority=1754 )755 except NotFound404Error as e:756 raise NotFound404Error from e757 except Exception as e:758 LOGGER.error(f"{e} Errored in reverification resumed!")759 k += 1760 if k > 5:761 return False762 LOGGER.info(f"Verified! Hash: {hash_id}")763 return True764 765 766@app.route("/app/files/<string:id_>", methods=["GET"])767def list_torrent_contents(id_):768 if "pin_code" not in request.args.keys():769 return code_page.replace("{form_url}", f"/app/files/{id_}")770 771 pincode = ""772 for nbr in id_:773 if nbr.isdigit():774 pincode += str(nbr)775 if len(pincode) == 4:776 break777 if request.args["pin_code"] != pincode:778 return "<h1>Incorrect pin code</h1>"779 780 if id_.startswith("SABnzbd_nzo"):781 782 async def get_files():783 res = await sabnzbd_client.get_files(id_)784 return res785 786 res = web_loop.run_until_complete(get_files())787 cont = make_tree(788 res,789 "nzb" # type: ignore790 )791 elif len(id_) > 20:792 res = qbittorrent_client.torrents_files(torrent_hash=id_)793 cont = make_tree(794 res,795 "qbit" # type: ignore796 )797 else:798 res = aria2.client.get_files(id_)799 cont = make_tree(800 res,801 "aria" # type: ignore802 )803 return page.replace(804 "{My_content}",805 cont[0]806 ).replace(807 "{form_url}",808 f"/app/files/{id_}?pin_code={pincode}"809 )810 811 812@app.route("/app/files/<string:id_>", methods=["POST"])813def set_priority(id_):814 data = dict(request.form)815 816 if id_.startswith("SABnzbd_nzo"):817 818 to_remove = []819 for i, value in data.items():820 if "filenode" in i and value != "on":821 node_no = i.split("_")[-1]822 to_remove.append(node_no)823 824 async def remove_files():825 await sabnzbd_client.remove_file(826 id_,827 to_remove828 )829 830 web_loop.run_until_complete(remove_files())831 LOGGER.info(f"Verified! nzo_id: {id_}")832 833 elif len(id_) > 20:834 resume = ""835 pause = ""836 for i, value in data.items():837 if "filenode" in i:838 node_no = i.split("_")[-1]839 840 if value == "on":841 resume += f"{node_no}|"842 else:843 pause += f"{node_no}|"844 845 pause = pause.strip("|")846 resume = resume.strip("|")847 848 try:849 qbittorrent_client.torrents_file_priority(850 torrent_hash=id_,851 file_ids=pause,852 priority=0853 )854 except NotFound404Error as e:855 raise NotFound404Error from e856 except Exception as e:857 LOGGER.error(f"{e} Errored in paused")858 try:859 qbittorrent_client.torrents_file_priority(860 torrent_hash=id_,861 file_ids=resume,862 priority=1863 )864 except NotFound404Error as e:865 raise NotFound404Error from e866 except Exception as e:867 LOGGER.error(f"{e} Errored in resumed")868 sleep(1)869 if not re_verfiy(870 pause,871 resume,872 id_873 ):874 LOGGER.error(f"Verification Failed! Hash: {id_}")875 else:876 resume = ""877 for i, value in data.items():878 if "filenode" in i and value == "on":879 node_no = i.split("_")[-1]880 resume += f"{node_no},"881 882 resume = resume.strip(",")883 884 res = aria2.client.change_option(885 id_,886 {"select-file": resume}887 )888 if res == "OK":889 LOGGER.info(f"Verified! Gid: {id_}")890 else:891 LOGGER.info(f"Verification Failed! Report! Gid: {id_}")892 return list_torrent_contents(id_)893 894 895@app.route("/")896def homepage():897 return "<h1>Visit my channel <a href='https://telegram.me/z_mirror'>@Z_Mirror</a>on Telegram By <a href='https://telegram.me/dawn_bharat'>@Dawn_Bharat</a></h1>"898 899 900@app.errorhandler(Exception)901def page_not_found(e):902 return (903 f"<h1>404: Task not found! Mostly wrong input. <br><br>Error: {e}</h2>",904 404,905 )906 907 908if __name__ == "__main__":909 app.run()910 