├── .github └── FUNDING.yml ├── README.md ├── _config.yml ├── kickass ├── rlab_utils.py ├── title_cloud_commander.png ├── title_jdownloader.png ├── title_qbittorrent.png ├── title_rclonelab.svg ├── title_youtube-dl.png └── torrentTOmega_gdrive - 改.ipynb ├── res ├── deluge │ ├── core.conf │ └── web.conf ├── jellyfin │ ├── data.tar.gz │ └── placeholder ├── pyload │ ├── files.db │ └── pyload.conf ├── scripts │ ├── doneCMD.sh │ └── simpleCloudInstaller.sh ├── ttmg.py └── utorrent │ └── utserver.conf ├── src ├── L3MON_DEMO.gif ├── aria2RpcConfigSetup.gif ├── aria2cli.png ├── cover.png ├── preview.gif ├── rclone_config_create.gif ├── spotify-downloader.png ├── sshPreview.gif └── zip.png ├── torrentTOmega_gdrive.ipynb └── update.xml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: biplobsutradhar # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | ![preview](https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/master/src/preview.gif) 4 | 5 | # Google-Colab-CloudTorrent Hits 6 | 7 | Features:
8 | `Simple Torrent, peerflix-server, deluge, aria2, ariang, rclone, rclone WebUI, Jdownloader, Youtube-dl, Netdata, Cloud Commander, 9 | Ssh, noVnc, filebrowser, µTorrent, Transmission Web Control, SocialFish, L3MON, SayCheese, spotify-downloader, pyLoad, qBittorrent, rTorrent, code-server, V2ray, Jellyfin ...` 10 | 11 | 12 | # Usage 13 | 1. Download notebook click it --> torrentTOmega_gdrive.ipynb 14 | 2. Goto https://colab.research.google.com 15 | 3. Upload the notebook (File>Upload notebook) and Select the notebook file to upload. 16 | 4. Done! 17 | 18 | ### Our telegram group 19 |
Telegram Group
20 | 21 | 22 | 23 |
Open
24 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /kickass/rlab_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import re # nosec 3 | import ipywidgets as widgets # pylint: disable=import-error 4 | from IPython.display import HTML, clear_output, display # pylint: disable=import-error 5 | from google.colab import files # pylint: disable=import-error 6 | from glob import glob 7 | from sys import exit as exx 8 | 9 | # Ultilities Methods ========================================================== 10 | 11 | 12 | def createButton(name, *, func=None, style="", icon="check"): 13 | import ipywidgets as widgets # pylint: disable=import-error 14 | 15 | button = widgets.Button( 16 | description=name, button_style=style, icon=icon, disabled=not bool(func) 17 | ) 18 | button.style.font_weight = "900" 19 | button.on_click(func) 20 | output = widgets.Output() 21 | display(button, output) 22 | 23 | 24 | def generateRandomStr(): 25 | from uuid import uuid4 26 | 27 | return str(uuid4()).split("-")[0] 28 | 29 | 30 | def checkAvailable(path_="", userPath=False): 31 | from os import path as _p 32 | 33 | if path_ == "": 34 | return False 35 | else: 36 | return ( 37 | _p.exists(path_) 38 | if not userPath 39 | else _p.exists(f"/usr/local/sessionSettings/{path_}") 40 | ) 41 | 42 | 43 | def findProcess(process, command="", isPid=False): 44 | from psutil import pids, Process # pylint: disable=import-error 45 | 46 | if isinstance(process, int): 47 | if process in pids(): 48 | return True 49 | else: 50 | for pid in pids(): 51 | try: 52 | p = Process(pid) 53 | if process in p.name(): 54 | for arg in p.cmdline(): 55 | if command in str(arg): 56 | return True if not isPid else str(pid) 57 | else: 58 | pass 59 | else: 60 | pass 61 | except: # nosec 62 | continue 63 | 64 | 65 | def runSh(args, *, output=False, shell=False): 66 | import subprocess 67 | import shlex # nosec 68 | 69 | if not shell: 70 | if output: 71 | proc = subprocess.Popen( # nosec 72 | shlex.split(args), stdout=subprocess.PIPE, stderr=subprocess.STDOUT 73 | ) 74 | while True: 75 | output = proc.stdout.readline() 76 | if output == b"" and proc.poll() is not None: 77 | return 78 | if output: 79 | print(output.decode("utf-8").strip()) 80 | return subprocess.run(shlex.split(args)).returncode # nosec 81 | else: 82 | if output: 83 | return ( 84 | subprocess.run( 85 | args, 86 | shell=True, # nosec 87 | stdout=subprocess.PIPE, 88 | stderr=subprocess.STDOUT, 89 | ) 90 | .stdout.decode("utf-8") 91 | .strip() 92 | ) 93 | return subprocess.run(args, shell=True).returncode # nosec 94 | 95 | 96 | def accessSettingFile(file="", setting={}): 97 | from json import load, dump 98 | 99 | if not isinstance(setting, dict): 100 | print("Only accept Dictionary object.") 101 | exx() 102 | fullPath = f"/usr/local/sessionSettings/{file}" 103 | try: 104 | if not len(setting): 105 | if not checkAvailable(fullPath): 106 | print(f"File unavailable: {fullPath}.") 107 | exx() 108 | with open(fullPath) as jsonObj: 109 | return load(jsonObj) 110 | else: 111 | with open(fullPath, "w+") as outfile: 112 | dump(setting, outfile) 113 | except: 114 | print(f"Error accessing the file: {fullPath}.") 115 | 116 | 117 | def memGiB(): 118 | from os import sysconf as _sc # pylint: disable=no-name-in-module 119 | 120 | return _sc("SC_PAGE_SIZE") * _sc("SC_PHYS_PAGES") / (1024.0 ** 3) 121 | 122 | 123 | # Prepare prerequisites ======================================================= 124 | 125 | 126 | def installQBittorrent(): 127 | if checkAvailable("/usr/bin/qbittorrent-nox"): 128 | return 129 | else: 130 | try: 131 | runSh("add-apt-repository ppa:qbittorrent-team/qbittorrent-stable -y") 132 | runSh("apt-get install qbittorrent-nox -qq -y") 133 | except: 134 | print("Error installing qBittorrent.") 135 | exx() 136 | 137 | 138 | def installNgrok(): 139 | if checkAvailable("/usr/local/bin/ngrok"): 140 | return 141 | else: 142 | runSh( 143 | "wget -qq -c -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip" 144 | ) 145 | runSh("unzip -qq -n ngrok-stable-linux-amd64.zip") 146 | runSh("mv ngrok /usr/local/bin/ngrok") 147 | runSh("rm -f /content/ngrok-stable-linux-amd64.zip") 148 | 149 | 150 | def installAutoSSH(): 151 | if checkAvailable("/usr/bin/autossh"): 152 | return 153 | else: 154 | runSh("apt-get install autossh -qq -y") 155 | 156 | 157 | def installJDownloader(): 158 | if checkAvailable("/root/.JDownloader/JDownloader.jar"): 159 | return 160 | else: 161 | runSh("mkdir -p -m 666 /root/.JDownloader/libs") 162 | runSh("apt-get install openjdk-8-jre-headless -qq -y") 163 | runSh( 164 | "wget -q http://installer.jdownloader.org/JDownloader.jar -O /root/.JDownloader/JDownloader.jar" 165 | ) 166 | runSh("java -jar /root/.JDownloader/JDownloader.jar -norestart -h") 167 | runSh( 168 | "wget -q https://biplobsd.github.io/RLabClone/res/jdownloader/sevenzipjbinding1509.jar -O /root/.JDownloader/libs/sevenzipjbinding1509.jar" 169 | ) 170 | runSh( 171 | "wget -q https://biplobsd.github.io/RLabClone/res/jdownloader/sevenzipjbinding1509Linux.jar -O /root/.JDownloader/libs/sevenzipjbinding1509Linux.jar" 172 | ) 173 | 174 | 175 | def installMkvTools(): 176 | if checkAvailable("/etc/apt/sources.list.d/mkvtoolnix.download.list"): 177 | return 178 | with open("/etc/apt/sources.list.d/mkvtoolnix.download.list", "w+") as outFile: 179 | outFile.write("deb https://mkvtoolnix.download/ubuntu/ bionic main") 180 | runSh( 181 | "wget -q -O - https://mkvtoolnix.download/gpg-pub-moritzbunkus.txt | sudo apt-key add - && sudo apt-get install mkvtoolnix mkvtoolnix-gui", 182 | shell=True, # nosec 183 | ) 184 | if not checkAvailable("/usr/bin/mediainfo"): 185 | runSh("apt-get install mediainfo") 186 | 187 | 188 | def installFilebot(installBackup=False): 189 | if not checkAvailable("/usr/bin/filebot"): 190 | if installBackup: 191 | if not checkAvailable("/usr/local/sessionSettings/fb/jar"): 192 | runSh( 193 | "curl -fsSL https://biplobsd.github.io/RLabClone/res/gdown.sh | bash -s 1OjSf-g8NxssKALp6zIJwJT7YamSVLGiR /usr/local/sessionSettings/fblx.7z \ 194 | && 7z x /usr/local/sessionSettings/fblx.7z -o/usr/local/sessionSettings/fb", 195 | shell=True, 196 | ) 197 | 198 | if not checkAvailable("/usr/share/filebot/bin"): 199 | runSh("mkdir -p -m 666 /usr/share/filebot/bin") 200 | runSh("mkdir -p -m 666 /usr/share/filebot/jar") 201 | runSh( 202 | "wget -q https://biplobsd.github.io/RLabClone/res/filebot -O /usr/bin/filebot" 203 | ) 204 | runSh("chmod +x /usr/bin/filebot") 205 | runSh("cp -r /usr/local/sessionSettings/fb/jar /usr/share/filebot") 206 | runSh( 207 | "cp -r /usr/local/sessionSettings/fb/filebot.sh /usr/share/filebot/bin/filebot.sh" 208 | ) 209 | else: 210 | runSh( 211 | "curl -fsSL https://raw.githubusercontent.com/filebot/plugins/master/installer/deb.sh | bash -s", 212 | shell=True, 213 | ) 214 | if checkAvailable("/usr/share/filebot/jar/filebot.jar"): 215 | runSh( 216 | "mv /usr/share/filebot/jar/filebot.jar /usr/share/filebot/jar/filebot.jar.bak" 217 | ) 218 | runSh( 219 | "wget -q https://biplobsd.github.io/RLabClone/res/filebot.jar -O /usr/share/filebot/jar/filebot.jar" 220 | ) 221 | 222 | 223 | def installRclone(): 224 | if not checkAvailable("/usr/bin/rclone"): 225 | runSh( 226 | "curl -s https://rclone.org/install.sh | sudo bash -s beta", 227 | shell=True, # nosec 228 | ) 229 | 230 | 231 | def checkServer(hostname): 232 | # nosec 233 | return True if runSh(f"ping -c 1 {hostname}", shell=True) == 0 else False 234 | 235 | 236 | def configTimezone(auto=True): 237 | if checkAvailable("timezone.txt", userPath=True): 238 | return 239 | if not auto: 240 | runSh("sudo dpkg-reconfigure tzdata") 241 | else: 242 | runSh("sudo ln -fs /usr/share/zoneinfo/Asia/Ho_Chi_Minh /etc/localtime") 243 | runSh("sudo dpkg-reconfigure -f noninteractive tzdata") 244 | data = {"timezone": "Asia/Ho_Chi_Minh"} 245 | accessSettingFile("timezone.txt", data) 246 | 247 | 248 | def uploadRcloneConfig(localUpload=False): 249 | if not localUpload and checkAvailable("rclone.conf", userPath=True): 250 | return 251 | elif not localUpload: 252 | runSh( 253 | "wget -qq https://biplobsd.github.io/RLabClone/res/rclonelab/rclone.conf \ 254 | -O /usr/local/sessionSettings/rclone.conf" 255 | ) 256 | else: 257 | try: 258 | print("Select config file (rclone.conf) from your computer.") 259 | uploadedFileName = files.upload().keys() 260 | if len(uploadedFileName) > 1: 261 | for fn in uploadedFileName: 262 | runSh(f'rm -f "/content/{fn}"') 263 | return print("Please only upload a single config file.") 264 | elif len(uploadedFileName) == 0: 265 | return print("File upload cancelled.") 266 | else: 267 | for fn in uploadedFileName: 268 | if checkAvailable(f"/content/{fn}"): 269 | runSh( 270 | f'mv -f "/content/{fn}" /usr/local/sessionSettings/rclone.conf' 271 | ) 272 | runSh("chmod 666 /usr/local/sessionSettings/rclone.conf") 273 | runSh('rm -f "/content/{fn}"') 274 | print("Uploaded file successfully.") 275 | 276 | except: 277 | return print("Upload process Error.") 278 | 279 | 280 | def uploadQBittorrentConfig(): 281 | if checkAvailable("updatedQBSettings.txt", userPath=True): 282 | return 283 | runSh( 284 | "mkdir -p -m 666 /content/qBittorrent /root/.qBittorrent_temp /root/.config/qBittorrent" 285 | ) 286 | runSh( 287 | "wget -qq https://biplobsd.github.io/RLabClone/res/qbittorrent/qBittorrent.conf \ 288 | -O /root/.config/qBittorrent/qBittorrent.conf" 289 | ) 290 | data = {"uploaded": "True"} 291 | accessSettingFile("updatedQBSettings.txt", data) 292 | 293 | 294 | def addUtils(): 295 | if checkAvailable("/content/sample_data"): 296 | runSh("rm -rf /content/sample_data") 297 | if not checkAvailable("/usr/local/sessionSettings"): 298 | runSh("mkdir -p -m 777 /usr/local/sessionSettings") 299 | if not checkAvailable("/content/upload.txt"): 300 | runSh("touch /content/upload.txt") 301 | if not checkAvailable("/root/.ipython/rlab_utils.py"): 302 | runSh( 303 | "wget -qq https://biplobsd.github.io/RLabClone/res/rlab_utils.py \ 304 | -O /root/.ipython/rlab_utils.py" 305 | ) 306 | if not checkAvailable("checkAptUpdate.txt", userPath=True): 307 | runSh("apt update -qq -y") 308 | runSh("apt-get install -y iputils-ping") 309 | data = {"apt": "updated", "ping": "installed"} 310 | accessSettingFile("checkAptUpdate.txt", data) 311 | 312 | 313 | def prepareSession(): 314 | if checkAvailable("ready.txt", userPath=True): 315 | return 316 | else: 317 | addUtils() 318 | configTimezone() 319 | uploadRcloneConfig() 320 | uploadQBittorrentConfig() 321 | installRclone() 322 | accessSettingFile("ready.txt", {"prepared": "True"}) 323 | 324 | 325 | # rClone ====================================================================== 326 | 327 | PATH_RClone_Config = "/usr/local/sessionSettings" 328 | 329 | 330 | def displayOutput(operationName="", color="#ce2121"): 331 | if color == "success": 332 | hColor = "#28a745" 333 | displayTxt = f"👍 Operation {operationName} has been successfully completed." 334 | elif color == "danger": 335 | hColor = "#dc3545" 336 | displayTxt = f"❌ Operation {operationName} has been errored." 337 | elif color == "info": 338 | hColor = "#17a2b8" 339 | displayTxt = f"👋 Operation {operationName} has some info." 340 | elif color == "warning": 341 | hColor = "#ffc107" 342 | displayTxt = f"⚠ Operation {operationName} has been warning." 343 | else: 344 | hColor = "#ffc107" 345 | displayTxt = f"{operationName} works." 346 | display( 347 | HTML( 348 | f""" 349 |
350 |

351 | {displayTxt} 352 |

353 |
354 |
355 | """ 356 | ) 357 | ) 358 | 359 | 360 | # qBittorrent ================================================================= 361 | 362 | QB_Port = 10001 363 | 364 | tokens = { 365 | "ddn": "6qGnEsrCL4GqZ7hMfqpyz_7ejAThUCjVnU9gD5pbP5u", 366 | "tdn": "1Q4i7F6isO7zZRrrjBKZzZhwsMu_74yJqoEs1HrJh1zYyxNo1", 367 | "mnc": "1QPZGQMEBBI1O3L8G1GtWUiphvF_2d3C6kux93P6p4Zy7SSib", 368 | "api001": "1Q3zMbZhIunjp92RvrZpnyuJxZL_3V3JUziX5Dp1sQbTMAPrr", 369 | "api002": "1Q45NXgsx6oyusN3GiNAYvkNJPS_AveYUDBcPHsvRvf21WZv", 370 | "api003": "1Q6smHt4Bzz9VEXTwj3a7p5Gdx2_5mp6ivT6N6nB3YmRHUEM3", 371 | } 372 | 373 | 374 | def displayUrl(data, buRemote, reset): 375 | clear_output(wait=True) 376 | print(f'Web UI: {data["url"]} : {data["port"]}') 377 | if "surl" in data.keys(): 378 | print(f'Web UI (S): {data["surl"]} : {data["port"]}') 379 | createButton("Backup Remote", func=buRemote) 380 | if "token" in data.keys(): 381 | createButton("Reset", func=reset) 382 | 383 | 384 | # JDownloader ================================================================= 385 | 386 | Email = widgets.Text(placeholder="*Required", description="Email:") 387 | Password = widgets.Text(placeholder="*Required", description="Password:") 388 | Device = widgets.Text(placeholder="Optional", description="Name:") 389 | SavePath = widgets.Dropdown( 390 | value="/content/Downloads", 391 | options=["/content", "/content/Downloads"], 392 | description="Save Path:", 393 | ) 394 | 395 | 396 | def refreshJDPath(a=1): 397 | if checkAvailable("/content/drive/"): 398 | if checkAvailable("/content/drive/Shared drives/"): 399 | SavePath.options = ( 400 | ["/content", "/content/Downloads", "/content/drive/My Drive"] 401 | + glob("/content/drive/My Drive/*/") 402 | + glob("/content/drive/Shared drives/*/") 403 | ) 404 | else: 405 | SavePath.options = [ 406 | "/content", 407 | "/content/Downloads", 408 | "/content/drive/My Drive", 409 | ] + glob("/content/drive/My Drive/*/") 410 | else: 411 | SavePath.options = ["/content", "/content/Downloads"] 412 | 413 | 414 | def exitJDWeb(): 415 | runSh("pkill -9 -e -f java") 416 | clear_output(wait=True) 417 | createButton("Start", func=startJDService, style="info") 418 | 419 | 420 | def confirmJDForm(a): 421 | clear_output(wait=True) 422 | action = a.description 423 | createButton(f"{action} Confirm?") 424 | if action == "Restart": 425 | createButton("Confirm", func=startJDService, style="danger") 426 | else: 427 | createButton("Confirm", func=exitJDWeb, style="danger") 428 | createButton("Cancel", func=displayJDControl, style="warning") 429 | 430 | 431 | def displayJDControl(a=1): 432 | clear_output(wait=True) 433 | createButton("Control Panel") 434 | display( 435 | HTML( 436 | """ 437 |

438 | You can login to the WebUI by clicking 439 | 440 | here 441 | . 442 |

443 | """ 444 | ), 445 | HTML( 446 | """ 447 |

448 | If the server didn't showup in 30 sec. please re-login. 449 |

450 | """ 451 | ), 452 | ) 453 | createButton("Re-Login", func=displayJDLoginForm, style="info") 454 | createButton("Restart", func=confirmJDForm, style="warning") 455 | createButton("Exit", func=confirmJDForm, style="danger") 456 | 457 | 458 | def startJDService(a=1): 459 | runSh("pkill -9 -e -f java") 460 | runSh( 461 | "java -jar /root/.JDownloader/JDownloader.jar -norestart -noerr -r &", 462 | shell=True, # nosec 463 | ) 464 | displayJDControl() 465 | 466 | 467 | def displayJDLoginForm(a=1): 468 | clear_output(wait=True) 469 | Email.value = "" 470 | Password.value = "" 471 | Device.value = "" 472 | refreshJDPath() 473 | display( 474 | HTML( 475 | """ 476 |

477 | If you don't have an account yet, please register 478 | 479 | here 480 | . 481 |

482 | """ 483 | ), 484 | HTML("
"), 485 | Email, 486 | Password, 487 | Device, 488 | SavePath, 489 | ) 490 | createButton("Refresh", func=refreshJDPath) 491 | createButton("Login", func=startJDFormLogin, style="info") 492 | if checkAvailable( 493 | "/root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json" 494 | ): 495 | createButton("Cancel", func=displayJDControl, style="danger") 496 | 497 | 498 | def startJDFormLogin(a=1): 499 | try: 500 | if not Email.value.strip(): 501 | ERROR = "Email field is empty." 502 | THROW_ERROR 503 | if not "@" in Email.value and not "." in Email.value: 504 | ERROR = "Email is an incorrect format." 505 | THROW_ERROR 506 | if not Password.value.strip(): 507 | ERROR = "Password field is empty." 508 | THROW_ERROR 509 | if not bool(re.match("^[a-zA-Z0-9]+$", Device.value)) and Device.value.strip(): 510 | ERROR = "Only alphanumeric are allowed for the device name." 511 | THROW_ERROR 512 | clear_output(wait=True) 513 | if SavePath.value == "/content": 514 | savePath = {"defaultdownloadfolder": "/content/Downloads"} 515 | elif SavePath.value == "/content/Downloads": 516 | runSh("mkdir -p -m 666 /content/Downloads") 517 | savePath = {"defaultdownloadfolder": "/content/Downloads"} 518 | else: 519 | savePath = {"defaultdownloadfolder": SavePath.value} 520 | 521 | with open( 522 | "/root/.JDownloader/cfg/org.jdownloader.settings.GeneralSettings.json", "w+" 523 | ) as outPath: 524 | json.dump(savePath, outPath) 525 | if Device.value.strip() == "": 526 | Device.value = Email.value 527 | runSh("pkill -9 -e -f java") 528 | data = { 529 | "email": Email.value, 530 | "password": Password.value, 531 | "devicename": Device.value, 532 | "directconnectmode": "LAN", 533 | } 534 | with open( 535 | "/root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json", 536 | "w+", 537 | ) as outData: 538 | json.dump(data, outData) 539 | startJDService() 540 | except: 541 | print(ERROR) 542 | 543 | 544 | def handleJDLogin(newAccount): 545 | installJDownloader() 546 | if newAccount: 547 | displayJDLoginForm() 548 | else: 549 | data = { 550 | "email": "daniel.dungngo@gmail.com", 551 | "password": "ZjPNiqjL4e6ckwM", 552 | "devicename": "daniel.dungngo@gmail.com", 553 | "directconnectmode": "LAN", 554 | } 555 | with open( 556 | "/root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json", 557 | "w+", 558 | ) as outData: 559 | json.dump(data, outData) 560 | startJDService() 561 | 562 | 563 | # TO DO === 564 | # Update MAKE BUTTON FUNCTIONS 565 | # FINISH MAKING ICONS 566 | # 567 | -------------------------------------------------------------------------------- /kickass/title_cloud_commander.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/kickass/title_cloud_commander.png -------------------------------------------------------------------------------- /kickass/title_jdownloader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/kickass/title_jdownloader.png -------------------------------------------------------------------------------- /kickass/title_qbittorrent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/kickass/title_qbittorrent.png -------------------------------------------------------------------------------- /kickass/title_rclonelab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /kickass/title_youtube-dl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/kickass/title_youtube-dl.png -------------------------------------------------------------------------------- /res/deluge/core.conf: -------------------------------------------------------------------------------- 1 | { 2 | "file": 1, 3 | "format": 1 4 | }{ 5 | "info_sent": 0.0, 6 | "lsd": true, 7 | "send_info": false, 8 | "move_completed_path": "/content/drive/My Drive", 9 | "enc_in_policy": 2, 10 | "queue_new_to_top": false, 11 | "ignore_limits_on_local_network": true, 12 | "rate_limit_ip_overhead": true, 13 | "daemon_port": 58846, 14 | "natpmp": true, 15 | "max_active_limit": 8, 16 | "utpex": true, 17 | "max_active_downloading": 3, 18 | "max_active_seeding": 5, 19 | "allow_remote": true, 20 | "max_half_open_connections": 50, 21 | "download_location": "/content/downloads/", 22 | "compact_allocation": false, 23 | "max_upload_speed": -1.0, 24 | "cache_expiry": 60, 25 | "prioritize_first_last_pieces": false, 26 | "auto_managed": true, 27 | "enc_level": 0, 28 | "max_connections_per_second": 20, 29 | "dont_count_slow_torrents": false, 30 | "random_outgoing_ports": true, 31 | "max_upload_slots_per_torrent": -1, 32 | "new_release_check": false, 33 | "enc_out_policy": 2, 34 | "outgoing_ports": [ 35 | 0, 36 | 0 37 | ], 38 | "seed_time_limit": 180, 39 | "cache_size": 512, 40 | "share_ratio_limit": 2.0, 41 | "max_download_speed": -1.0, 42 | "geoip_db_location": "/usr/share/GeoIP/GeoIP.dat", 43 | "torrentfiles_location": "/root/Downloads", 44 | "stop_seed_at_ratio": false, 45 | "peer_tos": "0x00", 46 | "listen_interface": "", 47 | "upnp": true, 48 | "max_download_speed_per_torrent": -1, 49 | "max_upload_slots_global": 4, 50 | "enabled_plugins": [], 51 | "random_port": true, 52 | "autoadd_enable": false, 53 | "max_connections_global": -1, 54 | "enc_prefer_rc4": false, 55 | "listen_ports": [ 56 | 6881, 57 | 6891 58 | ], 59 | "dht": true, 60 | "stop_seed_ratio": 2.0, 61 | "seed_time_ratio_limit": 7.0, 62 | "max_upload_speed_per_torrent": -1, 63 | "copy_torrent_file": false, 64 | "del_copy_torrent_file": false, 65 | "move_completed": true, 66 | "proxies": { 67 | "peer": { 68 | "username": "", 69 | "password": "", 70 | "type": 0, 71 | "hostname": "", 72 | "port": 8080 73 | }, 74 | "web_seed": { 75 | "username": "", 76 | "password": "", 77 | "type": 0, 78 | "hostname": "", 79 | "port": 8080 80 | }, 81 | "tracker": { 82 | "username": "", 83 | "password": "", 84 | "type": 0, 85 | "hostname": "", 86 | "port": 8080 87 | }, 88 | "dht": { 89 | "username": "", 90 | "password": "", 91 | "type": 0, 92 | "hostname": "", 93 | "port": 8080 94 | } 95 | }, 96 | "add_paused": false, 97 | "max_connections_per_torrent": -1, 98 | "remove_seed_at_ratio": false, 99 | "autoadd_location": "/root/Downloads", 100 | "plugins_location": "/root/.config/deluge/plugins" 101 | } 102 | -------------------------------------------------------------------------------- /res/deluge/web.conf: -------------------------------------------------------------------------------- 1 | { 2 | "file": 1, 3 | "format": 1 4 | }{ 5 | "port": 8112, 6 | "enabled_plugins": [], 7 | "pwd_sha1": "2ce1a410bcdcc53064129b6d950f2e9fee4edc1e", 8 | "theme": "gray", 9 | "show_sidebar": true, 10 | "sidebar_show_zero": false, 11 | "pkey": "ssl/daemon.pkey", 12 | "https": false, 13 | "sessions": { 14 | "c3d5852ee424511a8693604be103c1ee": { 15 | "login": "admin", 16 | "expires": 1575635788.0, 17 | "level": 10 18 | }, 19 | "9b324079dbafe9e6a2c3c6d2078fd06d": { 20 | "login": "admin", 21 | "expires": 1575538995.0, 22 | "level": 10 23 | } 24 | }, 25 | "base": "/", 26 | "interface": "0.0.0.0", 27 | "pwd_salt": "c26ab3bbd8b137f99cd83c2c1c0963bcc1a35cad", 28 | "show_session_speed": false, 29 | "first_login": false, 30 | "cert": "ssl/daemon.cert", 31 | "session_timeout": 99999, 32 | "default_daemon": "", 33 | "sidebar_multiple_filters": true 34 | } 35 | -------------------------------------------------------------------------------- /res/jellyfin/data.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/res/jellyfin/data.tar.gz -------------------------------------------------------------------------------- /res/jellyfin/placeholder: -------------------------------------------------------------------------------- 1 | #placeholder 2 | -------------------------------------------------------------------------------- /res/pyload/files.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/res/pyload/files.db -------------------------------------------------------------------------------- /res/pyload/pyload.conf: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | download - "Download": 4 | int chunks : "Max connections for one download" = 3 5 | str interface : "Download interface to bind (ip or Name)" = None 6 | bool ipv6 : "Allow IPv6" = False 7 | bool limit_speed : "Limit Download Speed" = False 8 | int max_downloads : "Max Parallel Downloads" = 16 9 | int max_speed : "Max Download Speed in kb/s" = -1 10 | bool skip_existing : "Skip already existing files" = False 11 | 12 | downloadTime - "Download Time": 13 | time end : "End" = 0:00 14 | time start : "Start" = 0:00 15 | 16 | general - "General": 17 | bool checksum : "Use Checksum" = False 18 | bool debug_mode : "Debug Mode" = False 19 | folder download_folder : "Download Folder" = /content/downloads 20 | bool folder_per_package : "Create folder for each package" = True 21 | en;de;fr;it;es;nl;sv;ru;pl;cs;sr;pt_BR language : "Language" = en 22 | int min_free_space : "Min Free Space (MB)" = 200 23 | int renice : "CPU Priority" = 0 24 | 25 | log - "Log": 26 | bool file_log : "File Log" = True 27 | int log_count : "Count" = 5 28 | folder log_folder : "Folder" = Logs 29 | bool log_rotate : "Log Rotate" = True 30 | int log_size : "Size in kb" = 100 31 | 32 | permission - "Permissions": 33 | bool change_dl : "Change Group and User of Downloads" = False 34 | bool change_file : "Change file mode of downloads" = False 35 | bool change_group : "Change group of running process" = False 36 | bool change_user : "Change user of running process" = False 37 | str file : "Filemode for Downloads" = 0644 38 | str folder : "Folder Permission mode" = 0755 39 | str group : "Groupname" = users 40 | str user : "Username" = user 41 | 42 | proxy - "Proxy": 43 | str address : "Address" = "localhost" 44 | password password : "Password" = None 45 | int port : "Port" = 7070 46 | bool proxy : "Use Proxy" = False 47 | http;socks4;socks5 type : "Protocol" = http 48 | str username : "Username" = None 49 | 50 | reconnect - "Reconnect": 51 | bool activated : "Use Reconnect" = False 52 | time endTime : "End" = 0:00 53 | str method : "Method" = None 54 | time startTime : "Start" = 0:00 55 | 56 | remote - "Remote": 57 | bool activated : "Activated" = False 58 | ip listenaddr : "Adress" = 0.0.0.0 59 | bool nolocalauth : "No authentication on local connections" = False 60 | int port : "Port" = 7227 61 | 62 | ssl - "SSL": 63 | bool activated : "Activated" = False 64 | file cert : "SSL Certificate" = ssl.crt 65 | file key : "SSL Key" = ssl.key 66 | 67 | webinterface - "Webinterface": 68 | bool activated : "Activated" = True 69 | bool basicauth : "Use basic auth" = False 70 | ip host : "IP" = 0.0.0.0 71 | bool https : "Use HTTPS" = False 72 | int port : "Port" = 8000 73 | str prefix : "Path Prefix" = 74 | builtin;threaded;fastcgi;lightweight server : "Server" = builtin 75 | pyplex;classic;modern template : "Template" = modern 76 | -------------------------------------------------------------------------------- /res/scripts/doneCMD.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | UP="${CLD_DIR}/${CLD_PATH}" 4 | 5 | if [[ -d ${UP} ]]; then 6 | exit 0 7 | fi 8 | 9 | #Upload to Gdrive 10 | mkdir -p "/content/drive/My Drive/$(dirname "${CLD_PATH}")" 11 | mv "${UP}" "/content/drive/My Drive/${CLD_PATH}" 12 | -------------------------------------------------------------------------------- /res/scripts/simpleCloudInstaller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | TMP_DIR="/tmp/tmpinstalldir" 3 | function cleanup { 4 | echo rm -rf $TMP_DIR > /dev/null 5 | } 6 | function fail { 7 | cleanup 8 | msg=$1 9 | echo "============" 10 | echo "Error: $msg" 1>&2 11 | exit 1 12 | } 13 | function install { 14 | #settings 15 | BASE_URL="https://github.com/boypt/simple-torrent" 16 | if [ -z "$1" ] 17 | then 18 | LATEST_TAG=$(curl -s "${BASE_URL}/releases/latest" | sed -En 's/.+\/tag\/([.0-9A-Za-z]+)".+/\1/p') 19 | else 20 | LATEST_TAG="$1" 21 | fi 22 | USER="boypt" 23 | PROG="cloud-torrent" 24 | MOVE="true" 25 | RELEASE="$LATEST_TAG" 26 | INSECURE="false" 27 | OUT_DIR="/usr/local/bin" 28 | GH="https://github.com" 29 | #bash check 30 | [ ! "$BASH_VERSION" ] && fail "Please use bash instead" 31 | [ ! -d $OUT_DIR ] && fail "output directory missing: $OUT_DIR" 32 | #dependency check, assume we are a standard POISX machine 33 | which find > /dev/null || fail "find not installed" 34 | which xargs > /dev/null || fail "xargs not installed" 35 | which sort > /dev/null || fail "sort not installed" 36 | which tail > /dev/null || fail "tail not installed" 37 | which cut > /dev/null || fail "cut not installed" 38 | which du > /dev/null || fail "du not installed" 39 | GET="" 40 | if which curl > /dev/null; then 41 | GET="curl" 42 | if [[ $INSECURE = "true" ]]; then GET="$GET --insecure"; fi 43 | GET="$GET --fail -# -L" 44 | elif which wget > /dev/null; then 45 | GET="wget" 46 | if [[ $INSECURE = "true" ]]; then GET="$GET --no-check-certificate"; fi 47 | GET="$GET -qO-" 48 | else 49 | fail "neither wget/curl are installed" 50 | fi 51 | #find OS #TODO BSDs and other posixs 52 | case `uname -s` in 53 | Darwin) OS="darwin";; 54 | Linux) OS="linux";; 55 | *) fail "unknown os: $(uname -s)";; 56 | esac 57 | #find ARCH 58 | if uname -m | grep 64 > /dev/null; then 59 | ARCH="amd64" 60 | elif uname -m | grep arm > /dev/null; then 61 | ARCH="arm" 62 | elif uname -m | grep 386 > /dev/null; then 63 | ARCH="386" 64 | else 65 | fail "unknown arch: $(uname -m)" 66 | fi 67 | #choose from asset list 68 | URL="" 69 | FTYPE="" 70 | case "${OS}_${ARCH}" in 71 | "darwin_amd64") 72 | URL="https://github.com/boypt/simple-torrent/releases/download/$LATEST_TAG/cloud-torrent_linux_amd64.gz" 73 | FTYPE=".gz" 74 | ;; 75 | "linux_386") 76 | URL="https://github.com/boypt/simple-torrent/releases/download/$LATEST_TAG/cloud-torrent_linux_386.gz" 77 | FTYPE=".gz" 78 | ;; 79 | "linux_amd64") 80 | URL="https://github.com/boypt/simple-torrent/releases/download/$LATEST_TAG/cloud-torrent_linux_amd64.gz" 81 | FTYPE=".gz" 82 | ;; 83 | "linux_arm") 84 | URL="https://github.com/boypt/simple-torrent/releases/download/$LATEST_TAG/cloud-torrent_linux_arm.gz" 85 | FTYPE=".gz" 86 | ;; 87 | *) fail "No asset for platform ${OS}-${ARCH}";; 88 | esac 89 | #got URL! download it... 90 | echo "Installing $USER/$PROG $RELEASE..." 91 | #enter tempdir 92 | mkdir -p $TMP_DIR 93 | cd $TMP_DIR 94 | if [[ $FTYPE = ".gz" ]]; then 95 | which gzip > /dev/null || fail "gzip is not installed" 96 | #gzipped binary 97 | NAME="${PROG}_${OS}_${ARCH}.gz" 98 | GZURL="$GH/releases/download/$RELEASE/$NAME" 99 | #gz download! 100 | bash -c "$GET $URL" | gzip -d - > $PROG || fail "download failed" 101 | elif [[ $FTYPE = ".tar.gz" ]] || [[ $FTYPE = ".tgz" ]]; then 102 | #check if archiver progs installed 103 | which tar > /dev/null || fail "tar is not installed" 104 | which gzip > /dev/null || fail "gzip is not installed" 105 | bash -c "$GET $URL" | tar zxf - || fail "download failed" 106 | elif [[ $FTYPE = ".zip" ]]; then 107 | which unzip > /dev/null || fail "unzip is not installed" 108 | bash -c "$GET $URL" > tmp.zip || fail "download failed" 109 | unzip -o -qq tmp.zip || fail "unzip failed" 110 | rm tmp.zip || fail "cleanup failed" 111 | elif [[ $FTYPE = "" ]]; then 112 | bash -c "$GET $URL" > "cloud-torrent_${OS}_${ARCH}" || fail "download failed" 113 | else 114 | fail "unknown file type: $FTYPE" 115 | fi 116 | #search subtree largest file (bin) 117 | TMP_BIN=$(find . -type f | xargs du | sort -n | tail -n 1 | cut -f 2) 118 | if [ ! -f "$TMP_BIN" ]; then 119 | fail "could not find downloaded binary" 120 | fi 121 | #ensure its larger than 2MB 122 | if [[ $(du -m $TMP_BIN | cut -f1) -lt 2 ]]; then 123 | fail "resulting file is smaller than 2MB, not a go binary" 124 | fi 125 | #move into PATH or cwd 126 | chmod +x $TMP_BIN || fail "chmod +x failed" 127 | mv $TMP_BIN $OUT_DIR/$PROG || fail "mv failed" #FINAL STEP! 128 | echo "Installed at $OUT_DIR/$PROG" 129 | #done 130 | cleanup 131 | } 132 | install "$1" 133 | -------------------------------------------------------------------------------- /res/ttmg.py: -------------------------------------------------------------------------------- 1 | import os 2 | from sys import exit as exx 3 | import time 4 | import uuid 5 | import re 6 | from subprocess import Popen,PIPE 7 | 8 | HOME = os.path.expanduser("~") 9 | CWD = os.getcwd() 10 | 11 | # All found ngrok authtoken from github 12 | tokens = { 13 | "lostcatbox": "1f9tD7nftFEYssYeWFaP5ZO5tkL_5kaPxXbBJZT399uFXBkV7", 14 | "lostcatbox": "1X7aYWPuFKYzvewLbnNoMo71kZi_2uzbB966Q4TU5cpgNPKhy", 15 | "zero-structure": "1UqHsShi6o3ketf426P5UtVdTfs_5XFD6sFRMkryka8fAbLd3", 16 | "ekkleesia": "7LE18LK8zeaDYeybp5fKP_6GNG1oHEfhTnQE7s9qpw", 17 | "SEARteam1928": "1Qe1IeySOQWSTnpQ3eFfr8j7Oi5_2zhanqnpZwHBhsfANd6yf", 18 | "angenalZZZ": "7pWLVhS1gxiMAQdaFeYJy_31krnw9drNLLJftaNSFnm", 19 | "lukikrk": "1XJNNnG8kZsPjjFmLsYNWCC0gIo_7VpBhwTcvhiuK4o2G2jbt", 20 | "bhavya7777": "1XzP70k7YVrg7MMaHQWPks0Q8Za_7y6b1mTDJDmJWcuqt5qTp", 21 | "hector605": "1Y14GB7E4acXxWYnVTiBejgnLuV_853z7mAgaTJxE9KY3HnCW", 22 | "fouille": "1XkoKNLcyiPECcQfGUjrTVzN64P_7tv2YgC4DSnazyVtpCpHm", 23 | "rikitz": "1Xc7z0uHxDoI9Ah06EQKgH61zoP_6WTPXDGvjFmcp2o7gNmqa", 24 | "VictorM369": "3c4WZaxPbjeRwRibY5opU_2N4TTRKaDubtEWMeKkFXn", 25 | "YHF7": "3fW4eXHdUN3ziCBXcahZ_3tnDdaTyLw8tKzJtKZkLp", 26 | "cyberkallan": "3CqeFZQht43cG5Z2YKfyv_6aKTrgrbo1HtyRi78hRKK", 27 | "Toxic-Omega": "1RCQwctVjSz8AIzHO6S55jm8XB8_5N6PqyZVnoN7mUVqF1yvT", 28 | "DevLuDaley": "1XTxsRKP8XyxvaJigX9XFXU2FvK_4dqzLxNRJHBz8A3aoPC85", 29 | "randyramig": "3Y8YSw6bvC9CsbYeRczmt_8akMuLYA3bAUshP1NCMnW", 30 | "sz-xcf": "1XSYq8gmxzNgMlYQzERmC50uBot_6qURZnj43KsYF2GWaUamm", 31 | "api1": "6qGnEsrCL4GqZ7hMfqpyz_7ejAThUCjVnU9gD5pbP5u", 32 | "api2": "1Q4i7F6isO7zZRrrjBKZzZhwsMu_74yJqoEs1HrJh1zYyxNo1", 33 | "api3": "1SCsbuawjv9d79jlhlfNljaFTaB_5heVkcR6C7Sk8UBaQ1U1C", 34 | "api4": "1f9tD7nftFEYssYeWFaP5ZO5tkL_5kaPxXbBJZT399uFXBkV7", 35 | "api5": "1Q45NXgsx6oyusN3GiNAYvkNJPS_AveYUDBcPHsvRvf21WZv", 36 | "api6": "1Q6smHt4Bzz9VEXTwj3a7p5Gdx2_5mp6ivT6N6nB3YmRHUEM3", 37 | "api7": "7VJwGkCTTUubiGhgz6Gv6_5fMLganRSKj9ntdefnF5o", 38 | "api9": "5S28rBKgc22ZW7evyedNT_YvEm15RZSHdXgS4QwYbk", 39 | "api12": "3VnrrXDQVHoNp9HvHFhqX_3X4JExwm6L9n6w4ppL1qy", 40 | "api13": "1ShshNwfhQcyOqlMjnBDVE5X5jC_3WAmzomMHAgkunka4dSck", 41 | "api14": "772yFAui6ynH9AYx29HHS_5Xcr88pHtPTQLwewv7Ctk", 42 | "api16": "5HmAWwzDdkYp8CdzDQMDS_4BGwsK7AdMssLnSttZEeh", 43 | "api17": "1T750atJi3xccndeUqJ4ewiS62o_2s6f8GUccL1qDUXTGSftN", 44 | "api18": "1QUysRUo97w5mdB6sCZvTTMM0aK_3unoMs6nYd7grgCkuhbj3", 45 | "api19": "3CqeFZQht43cG5Z2YKfyv_6aKTrgrbo1HtyRi78hRKK", 46 | "api20": "5eMywZLisJNdybqpFLVgs_4XQDeF3YCMHu1Ybf7mVE6", 47 | "api21": "4Cg1cEwCT7Ek89zT4VcdB_4GPAjMFgu6nhwY7SxQm94", 48 | "api22": "1SGs4s9NrhxP9FRURszjL1nITSv_otcpfpb6aMVEL13u3dv1", 49 | "api23": "1StL3sIccfR624Uc3BGV36XA0qG_6cAMMYFdKtPjtWax3AHSK", 50 | "api24": "1SuK2ukM9Z4NohoJbU9224uMzXr_6h1ABdCrJU2EviZv4RN4r", 51 | "api26": "7ecmt2Kux5uYsTUHrrqGU_3W9CJnaSeSyxiwkjxNhHc", 52 | "api27": "3CqeFZQht43cG5Z2YKfyv_6aKTrgrbo1HtyRi78hRKK", 53 | "api28": "2DXURjrUhAZZNMhqN5m1F_6HHzejcfRecP8upwJnNBd" 54 | } 55 | 56 | 57 | class ngrok: 58 | 59 | def __init__(self, TOKEN=None, USE_FREE_TOKEN=True, 60 | service=[['Service1', 80, 'tcp'], ['Service2', 8080, 'tcp']], 61 | region='us', 62 | dBug=[f"{HOME}/.ngrok2/ngrok.yml", 4040]): 63 | self.region = region 64 | self.configPath, self.dport = dBug 65 | self.TOKEN = TOKEN 66 | self.USE_FREE_TOKEN = USE_FREE_TOKEN 67 | self.service = service 68 | if USE_FREE_TOKEN: 69 | self.sdict = {} 70 | for i, sn in enumerate(service): 71 | tempcP = f'{HOME}/.ngrok2/'+sn[0]+'.yml' 72 | # Port, Protocol, config path 73 | self.sdict[sn[0]] = [self.dport+i, sn[2], tempcP] 74 | 75 | def nameport(self, TOKEN, AUTO): 76 | if AUTO: 77 | try: 78 | return tokens.popitem()[1] 79 | except KeyError: 80 | return "Invalid Token" 81 | elif not TOKEN: 82 | if not 'your' in tokens.keys(): 83 | from IPython import get_ipython 84 | from IPython.display import clear_output 85 | ipython = get_ipython() 86 | 87 | print(r"Copy authtoken from https://dashboard.ngrok.com/auth") 88 | __temp = ipython.magic('%sx read -p "Token :"') 89 | tokens['your'] = __temp[0].split(':')[1] 90 | USR_Api = "your" 91 | clear_output() 92 | else: 93 | USR_Api = "your" 94 | else: 95 | USR_Api = "mind" 96 | tokens["mind"] = TOKEN 97 | return tokens[USR_Api] 98 | 99 | 100 | def ngrok_config(self, token, Gport, configPath, region, service): 101 | import os 102 | data = """ 103 | region: {} 104 | update: false 105 | update_channel: stable 106 | web_addr: localhost:{} 107 | tunnels:\n""".format(region, Gport) 108 | if not self.USE_FREE_TOKEN: 109 | auth =""" 110 | authtoken: {}""".format(token) 111 | data = auth+data 112 | tunnels = "" 113 | for S in service: 114 | Sn, Sp, SpC = S 115 | tunnels += """ {}: 116 | addr: {} 117 | proto: {} 118 | inspect: false\n""".format(Sn, Sp, SpC) 119 | data = data + tunnels 120 | os.makedirs(f'{HOME}/.ngrok2/', exist_ok=True) 121 | with open(configPath, "w+") as configFile: 122 | configFile.write(data) 123 | return True 124 | 125 | 126 | def startWebUi(self, token, dport, nServer, region, btc, configPath, 127 | displayB, service, v): 128 | import os, time, urllib 129 | from IPython.display import clear_output 130 | from json import loads 131 | 132 | if token == "Invalid Token": 133 | print(tokens) 134 | os.exit() 135 | 136 | installNgrok() 137 | if v: 138 | clear_output() 139 | loadingAn(name="lds") 140 | textAn("Starting ngrok ...", ty='twg') 141 | if self.USE_FREE_TOKEN: 142 | for sn in service: 143 | self.ngrok_config( 144 | token, 145 | self.sdict[nServer][0], 146 | self.sdict[nServer][2], 147 | region, 148 | service) 149 | if sn[0] == nServer: 150 | runSh(f"ngrok {sn[2]} -config={self.sdict[nServer][2]} {sn[1]} &", shell=True) 151 | else: 152 | self.ngrok_config(token, dport, configPath, region, service) 153 | runSh(f"ngrok start --config {configPath} --all &", shell=True) 154 | time.sleep(3) 155 | try: 156 | if self.USE_FREE_TOKEN: 157 | dport = self.sdict[nServer][0] 158 | nServer = 'command_line' 159 | host = urllib.request.urlopen(f"http://localhost:{dport}/api/tunnels") 160 | else: 161 | host = urllib.request.urlopen(f"http://localhost:{dport}/api/tunnels") 162 | host = loads(host.read())['tunnels'] 163 | for h in host: 164 | if h['name'] == nServer: 165 | host = h['public_url'][8:] 166 | break 167 | except urllib.error.URLError: 168 | if v: 169 | clear_output() 170 | loadingAn(name="lds") 171 | textAn("Ngrok Token is in used!. Again trying token ...", ty='twg') 172 | time.sleep(2) 173 | return True 174 | 175 | data = {"url": f"http://{host}"} 176 | if displayB: 177 | displayUrl(data, btc) 178 | return data 179 | 180 | 181 | def start(self, nServer, btc='b', displayB=True, v=True): 182 | import urllib 183 | from IPython.display import clear_output 184 | from json import loads 185 | 186 | try: 187 | nServerbk = nServer 188 | if self.USE_FREE_TOKEN: 189 | dport = self.sdict[nServer][0] 190 | nServer = 'command_line' 191 | else: 192 | dport = self.dport 193 | host = urllib.request.urlopen(f"http://localhost:{dport}/api/tunnels") 194 | host = loads(host.read())['tunnels'] 195 | for h in host: 196 | if h['name'] == nServer: 197 | host = h['public_url'][8:] 198 | data = {"url": f"http://{host}"} 199 | if displayB: 200 | displayUrl(data, btc) 201 | return data 202 | 203 | raise Exception('Not found tunnels') 204 | except urllib.error.URLError: 205 | for run in range(10): 206 | if v: 207 | clear_output() 208 | loadingAn(name='lds') 209 | dati = self.startWebUi( 210 | self.nameport(self.TOKEN, self.USE_FREE_TOKEN) if not self.USE_FREE_TOKEN else {}, 211 | self.dport, 212 | nServerbk, 213 | self.region, 214 | btc, 215 | self.configPath, 216 | displayB, 217 | self.service, 218 | v 219 | ) 220 | if dati == True: 221 | continue 222 | return dati 223 | 224 | def checkAvailable(path_="", userPath=False): 225 | from os import path as _p 226 | 227 | if path_ == "": 228 | return False 229 | else: 230 | return ( 231 | _p.exists(path_) 232 | if not userPath 233 | else _p.exists(f"/usr/local/sessionSettings/{path_}") 234 | ) 235 | 236 | def accessSettingFile(file="", setting={}, v=True): 237 | from json import load, dump 238 | 239 | if not isinstance(setting, dict): 240 | if v:print("Only accept Dictionary object.") 241 | exx() 242 | fullPath = f"/usr/local/sessionSettings/{file}" 243 | try: 244 | if not len(setting): 245 | if not checkAvailable(fullPath): 246 | if v:print(f"File unavailable: {fullPath}.") 247 | exx() 248 | with open(fullPath) as jsonObj: 249 | return load(jsonObj) 250 | else: 251 | with open(fullPath, "w+") as outfile: 252 | dump(setting, outfile) 253 | except: 254 | if v:print(f"Error accessing the file: {fullPath}.") 255 | 256 | 257 | def displayUrl(data, btc='b', pNamU='Public URL: ', EcUrl=None, ExUrl=None, cls=True): 258 | from IPython.display import HTML, clear_output 259 | 260 | if cls: 261 | clear_output() 262 | showTxT = f'{pNamU}{data["url"]}' 263 | if EcUrl: 264 | showUrL = data["url"]+EcUrl 265 | elif ExUrl: 266 | showUrL = ExUrl 267 | else: 268 | showUrL = data["url"] 269 | if btc == 'b': 270 | # blue 271 | bttxt = 'hsla(210, 50%, 85%, 1)' 272 | btcolor = 'hsl(210, 80%, 42%)' 273 | btshado = 'hsla(210, 40%, 52%, .4)' 274 | elif btc == 'g': 275 | # green 276 | bttxt = 'hsla(110, 50%, 85%, 1)' 277 | btcolor = 'hsla(110, 86%, 56%, 1)' 278 | btshado = 'hsla(110, 40%, 52%, .4)' 279 | elif btc == 'r': 280 | # red 281 | bttxt = 'hsla(10, 50%, 85%, 1)' 282 | btcolor = 'hsla(10, 86%, 56%, 1)' 283 | btshado = 'hsla(10, 40%, 52%, .4)' 284 | 285 | return display(HTML('''
''')) 286 | 287 | 288 | def findProcess(process, command="", isPid=False): 289 | from psutil import pids, Process 290 | 291 | if isinstance(process, int): 292 | if process in pids(): 293 | return True 294 | else: 295 | for pid in pids(): 296 | try: 297 | p = Process(pid) 298 | if process in p.name(): 299 | for arg in p.cmdline(): 300 | if command in str(arg): 301 | return True if not isPid else str(pid) 302 | else: 303 | pass 304 | else: 305 | pass 306 | except: 307 | continue 308 | 309 | def installNgrok(): 310 | if checkAvailable("/usr/local/bin/ngrok"): 311 | return 312 | else: 313 | import os 314 | from zipfile import ZipFile 315 | from urllib.request import urlretrieve 316 | 317 | ngURL = "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip" 318 | urlretrieve(ngURL, 'ngrok-amd64.zip') 319 | with ZipFile('ngrok-amd64.zip', 'r') as zip_ref: 320 | zip_ref.extractall('/usr/local/bin/') 321 | os.chmod('/usr/local/bin/ngrok', 0o755) 322 | os.unlink('ngrok-amd64.zip') 323 | 324 | def installAutoSSH(): 325 | if checkAvailable("/usr/bin/autossh"): 326 | return 327 | else: 328 | runSh("apt-get install autossh -qq -y") 329 | 330 | 331 | 332 | def runSh(args, *, output=False, shell=False, cd=None): 333 | import subprocess, shlex 334 | 335 | if not shell: 336 | if output: 337 | proc = subprocess.Popen( 338 | shlex.split(args), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cd 339 | ) 340 | while True: 341 | output = proc.stdout.readline() 342 | if output == b"" and proc.poll() is not None: 343 | return 344 | if output: 345 | print(output.decode("utf-8").strip()) 346 | return subprocess.run(shlex.split(args), cwd=cd).returncode 347 | else: 348 | if output: 349 | return ( 350 | subprocess.run( 351 | args, 352 | shell=True, 353 | stdout=subprocess.PIPE, 354 | stderr=subprocess.STDOUT, 355 | cwd=cd, 356 | ) 357 | .stdout.decode("utf-8") 358 | .strip() 359 | ) 360 | return subprocess.run(args, shell=True, cwd=cd).returncode 361 | 362 | def loadingAn(name="cal"): 363 | from IPython.display import HTML 364 | 365 | if name == "cal": 366 | return display(HTML('
')) 367 | elif name == "lds": 368 | return display(HTML('''
''')) 369 | 370 | def textAn(TEXT, ty='d'): 371 | from IPython.display import HTML 372 | 373 | if ty == 'd': 374 | return display(HTML('''
'''+TEXT+'''
''')) 375 | elif ty == 'twg': 376 | textcover = str(len(TEXT)*0.55) 377 | return display(HTML('''
'''+TEXT+'''
''')) 378 | 379 | def updateCheck(self, Version): 380 | class UpdateChecker(object): 381 | 382 | def __init__(self): 383 | getMessage = self.getMessage 384 | getVersion = self.getVersion 385 | 386 | def getVersion(self, currentTag): 387 | from urllib.request import urlopen 388 | from lxml.etree import XML 389 | 390 | url = self.URL 391 | update = urlopen(url).read() 392 | root = XML(update) 393 | cur_version = root.find(".//"+currentTag) 394 | current = cur_version.text 395 | return current 396 | 397 | def getMessage(self, messageTag): 398 | from urllib.request import urlopen 399 | from lxml.etree import XML 400 | 401 | url = self.URL 402 | update = urlopen(url).read() 403 | root = XML(update) 404 | mess = root.find(".//"+messageTag) 405 | message = mess.text 406 | return message 407 | 408 | check = UpdateChecker() 409 | check.URL = "https://raw.githubusercontent.com/biplobsd/Google-Colab-CloudTorrent/master/update.xml" 410 | currentVersion = check.getVersion("currentVersion") 411 | message = check.getMessage("message") 412 | 413 | if Version != currentVersion: 414 | from IPython.display import HTML 415 | 416 | print("Script Update Checker: Version "+currentVersion+" "+message+" Your version: "+Version+"") 417 | display(HTML('

Open Latest Version

')) 418 | return True 419 | else: 420 | print("Script Update Checker: Your script is up to date") 421 | 422 | class LocalhostRun: 423 | def __init__(self,port,id=None,interval=30,retries=30): 424 | import os 425 | filePath = "/usr/local/sessionSettings/localhostDB.json" 426 | if not os.path.exists(filePath): 427 | os.makedirs(filePath[:-16], exist_ok=True) 428 | open(filePath, 'w').close() 429 | installAutoSSH() 430 | if not id:id=str(uuid.uuid4())[:8] 431 | self.connection=None 432 | self.id=id 433 | self.port=port 434 | self.interval=interval 435 | self.retries=retries 436 | 437 | def start(self): 438 | if self.connection:self.connection.kill() 439 | self.connection=Popen(f"ssh -R 80:localhost:{self.port} {self.id}@ssh.localhost.run -o StrictHostKeyChecking=no".split(), stdout=PIPE, stdin=PIPE) 440 | try: 441 | return re.findall("http://(.*?.localhost.run)",self.connection.stdout.readline().decode("utf-8"))[0] 442 | except: 443 | raise Exception(self.connection.stdout.readline().decode("utf-8")) 444 | 445 | def keep_alive(self): 446 | # if self.connection:self.connection.kill() 447 | import urllib 448 | try: 449 | localhostOpenDB = dict(accessSettingFile("localhostDB.json", v=False)) 450 | except TypeError: 451 | localhostOpenDB = dict() 452 | 453 | if findProcess("autossh", f"80:localhost:{self.port}"): 454 | try: 455 | oldAddr = localhostOpenDB[str(self.port)] 456 | urllib.request.urlopen("http://"+oldAddr) 457 | return oldAddr 458 | except: 459 | pass 460 | 461 | self.connection=Popen(f"autossh -R 80:localhost:{self.port} {self.id}@ssh.localhost.run -o StrictHostKeyChecking=no -o ServerAliveInterval={self.interval} -o ServerAliveCountMax={self.retries}".split(), stdout=PIPE, stdin=PIPE) 462 | #print("ssh -R 80:localhost:{self.port} {self.id}@ssh.localhost.run -o StrictHostKeyChecking=no -o ServerAliveInterval={self.interval} -o ServerAliveCountMax={self.retries}") 463 | try: 464 | newAddr = re.findall("http://(.*?.localhost.run)",self.connection.stdout.readline().decode("utf-8"))[0] 465 | localhostOpenDB[str(self.port)] = newAddr 466 | accessSettingFile("localhostDB.json" , localhostOpenDB, v=False) 467 | return newAddr 468 | except: 469 | raise Exception(self.connection.stdout.readline().decode("utf-8")) 470 | 471 | def kill(self): 472 | self.connection.kill() 473 | 474 | 475 | class PortForward: 476 | def __init__(self,connections,region=None,SERVICE="localhost",TOKEN=None,USE_FREE_TOKEN=None,config=None): 477 | c=dict() 478 | for con in connections: 479 | c[con[0]]=dict(port=con[1],proto=con[2]) 480 | self.connections=c 481 | self.ngrok=ngrok(TOKEN,USE_FREE_TOKEN,connections,region,config) 482 | self.SERVICE = SERVICE 483 | 484 | def start(self,name,btc='b',displayB=True,v=True): 485 | from IPython.display import clear_output 486 | 487 | if self.SERVICE == "localhost": 488 | con=self.connections[name] 489 | port=con["port"] 490 | proto=con["proto"] 491 | if(proto=="tcp"): 492 | return self.ngrok.start(name,btc,displayB,v) 493 | else: 494 | if v: 495 | clear_output() 496 | loadingAn(name="lds") 497 | textAn("Starting localhost ...", ty="twg") 498 | data = dict(url="http://"+LocalhostRun(port).keep_alive()) 499 | if displayB: 500 | displayUrl(data, btc) 501 | return data 502 | elif self.SERVICE == "ngrok": 503 | return self.ngrok.start(name,btc,displayB,v) 504 | 505 | 506 | class PortForward_wrapper(PortForward): 507 | def __init__(self,SERVICE,TOKEN,USE_FREE_TOKEN,connections,region,config): 508 | super(self.__class__,self).__init__(connections,region,SERVICE,TOKEN,USE_FREE_TOKEN,config) 509 | -------------------------------------------------------------------------------- /res/utorrent/utserver.conf: -------------------------------------------------------------------------------- 1 | ########################################### 2 | ### ### 3 | ### Utorrent Server v3.0 Config File ### 4 | ### ### 5 | ### By Khizer Naeem ### 6 | ### khizernaeem@gmail.com ### 7 | ### Date: 29/12/2011 ### 8 | ### ### 9 | ########################################### 10 | ########################################### 11 | # Note: - Don't use quotes or double quotes when giving a value 12 | # - Don't add trailing / when specifying any directory 13 | 14 | ##################### 15 | ## Regular Settings # 16 | ##################### 17 | 18 | #bind_port (integer): 19 | # Default value: 6881. Port used for BitTorrent protocol. This can be any value in the range 1025-65000. 20 | bind_port: 6881 21 | 22 | #max_ul_rate (integer): 23 | # Default value: -1. Maximum total upload rate in kilobytes per second. -1 means unlimited. We recommend setting it to -1. 24 | max_ul_rate: 0 25 | 26 | #max_ul_rate_seed (integer): 27 | # Default value: -1. Maximum per-torrent upload rate when seeding, in kilobytes per second. -1 means unlimited. We recommend setting it to -1. 28 | max_ul_rate_seed: 0 29 | 30 | #conns_per_torrent (integer): 31 | # Default value: 50. Maximum number of connections for a given torrent. 32 | conns_per_torrent: 999 33 | 34 | #max_total_connections (integer): 35 | # Default value: 200. Maximum number of connection opened at the same time. 36 | max_total_connections: 999 37 | 38 | #auto_bandwidth_management (boolean): 39 | # Default value: true. If true, upload bandwidth is automatically throttled in order to not impact other applications using TCP/IP. 40 | auto_bandwidth_management: true 41 | 42 | #max_dl_rate (integer): 43 | # Default value: -1. Maximum total download rate in kilobytes per second. -1 means unlimited. We recommend setting it to -1. 44 | max_dl_rate: 0 45 | 46 | #seed_ratio (integer): 47 | # Default value: 0. Seed ratio in percent (%) (e.g. 100 means 100%). If not 0, seeding will stop after reaching this upload/download ratio. 48 | seed_ratio: 0 49 | 50 | #seed_time (integer): 51 | # Default value: 0. Time after which seeding will stop, in seconds. 0 means seeding won't stop. 52 | seed_time: 0 53 | 54 | 55 | ##################### 56 | # Internal Settings # 57 | ##################### 58 | 59 | #bind_ip (string): 60 | # IP address to use for socket connections. If not provided, a default IP address will be used. We do not recommend changing this value. 61 | 62 | #ut_webui_port (integer): 63 | # Default value: 8080. Port number where the utserver process accepts HTTP RPC API calls to support the µTorrent-compatible HTTP interface. 64 | ut_webui_port: 5454 65 | 66 | #token_auth_enable (boolean) 67 | # Default value: true. If true, the µTorrent HTTP interface defends against cross-site request forgeries. 68 | # If false, the µTorrent HTTP interface will not be protected in this manner. 69 | token_auth_enable: false 70 | 71 | #dir_root (string): 72 | # Default value: "". If not empty, dir_active, dir_completed, and dir_torrent_files are relative to this directory. 73 | dir_root: /opt/utorrent/data 74 | 75 | #dir_active (string): 76 | # Default value: "./". Directory in which currently downloaded data is saved. 77 | # Can be an absolute path or relative to dir_root or the current working directory if dir_root is not defined or an empty string. 78 | #dir_active: /content/downloads 79 | 80 | #dir_completed (string): 81 | # Default value: "". Directory where completed downloads are stored. 82 | dir_completed: 83 | 84 | #dir_download (string): 85 | # Default value: "". Optional directory where completed downloads can be stored, instead of in dir_completed. 86 | # If no value is specified for this setting, the value of dir_completed is used. 87 | # This option can be specified multiple times in the file - once for each directory to be designated as such. 88 | # This option can be used when adding torrents via the µTorrent HTTP interface, not via the SDK interface. 89 | # Use the action list-dirs to obtain a list of download directories from the µTorrent HTTP interface. 90 | # Use the option download_dir to specify which of these directories to use when adding a torrent by URL or file through the µTorrent HTTP interface; 91 | # The index of each entry will be in order in which each entry appears in utserver.conf 92 | dir_download: /content/downloads 93 | 94 | #dir_torrent_files (string): 95 | # Default value: "". Directory where torrent files are stored. If the empty string, the value of dir_active is used. 96 | dir_torrent_files: 97 | 98 | #dir_temp_files (string): 99 | # Default value: "". Directory where temporary files are stored. If the empty string, the value of dir_active is used. 100 | # Using a separate directory just for temporary files allows for deleting the files in this directory on boot and/or periodically. 101 | # The utserver process creates temporary files with a .utt extension, 102 | # if a value for this setting is specified, the utserver process will delete all files with that extension in that directory at process startup. 103 | # The value should specify a directory, not a symbolic link to a directory. 104 | dir_temp_files: 105 | 106 | #dir_autoload (string): 107 | # Default value: "". Directory where torrent files will be recognized and auto-loaded. If the empty string, auto-load is disabled. 108 | dir_autoload: /content/downloads 109 | 110 | #dir_autoload_delete (boolean): 111 | # Default value: false. If true, torrent files in the autoload directory will be deleted after being loaded, 112 | # else they will be renamed with an extension of .loaded. The dir_autoload setting must be specified for this setting to have an effect. 113 | dir_autoload_delete: false 114 | 115 | #upnp (boolean): 116 | # Default value: true. If true, UPNP functionality for mapping ports is used by utserver. We recommend setting this value to true. 117 | upnp: true 118 | 119 | #natpmp (boolean): 120 | # Default value: true. If true, NAT-PMP functionality for mapping ports is used by utserver. We recommend setting this value to true. 121 | natpmp: true 122 | 123 | #lsd (boolean): 124 | # Default value: true. If true, Local Service Discovery is enabled. We recommend setting this value to true. 125 | lsd: true 126 | 127 | #dht (boolean): 128 | # Default value: true. If true, Distributed Hash Table extension is enabled. We recommend setting this value to true. 129 | dht: true 130 | 131 | #pex (boolean): 132 | # Default value: true. If true, Peer Exchange extension is enabled. We recommend setting this value to true. 133 | pex: true 134 | 135 | #rate_limit_local_peers (boolean): 136 | # Default value: false. If true, rate limiting also applies to communications with peers in the local subnet. We recommend setting this value to false. 137 | rate_limit_local_peers: false 138 | 139 | #disk_cache_max_size (integer): 140 | # Default value: 0. Maximum amount of memory used by each of the read, write, and piece caches. Value is in megabytes. 141 | # If 0, accepts the SDK's default choices on selecting sizes of disk caches. Maximum value is 512. 142 | disk_cache_max_size: 0 143 | 144 | #preferred_interface (string): 145 | # Default value: "". If defined, name of network interface to be preferred, 146 | # when attempting to search among network interfaces for an external IP and hardware address. 147 | # If empty string, preferred interface is ignored. 148 | preferred_interface: 149 | 150 | #admin_name (string): 151 | # Default value: "admin". If defined, name that must be supplied (along with the password) when authenticating to the server via the HTTP interface. 152 | # This allows the administrator to define an initial non-default value for this name. 153 | # This value will not be applied from utserver.conf if settings.dat already exists. 154 | admin_name: admin 155 | 156 | #admin_password (string): 157 | # Default value: "". If defined, password that must be supplied (along with the name) when authenticating to the server via the HTTP interface. 158 | # This allows the administrator to define an initial non-default value for this password. 159 | # This value will not be applied from utserver.conf if settings.dat already exists. 160 | admin_password: admin 161 | 162 | #logmask (integer): 163 | # Default value: 0. A mask whose bits when set allow certain categories of log messages to be generated. 164 | # The bits (0 - 31) in the value of this setting correspond to a set of internal events and subsystems. 165 | # 166 | # 3 - send have 167 | # 6 - hole punch 168 | # 7 - got bad piece request 169 | # 8 - trace 170 | # 9 - piece picker 171 | # 10 - got bad cancel 172 | # 11 - got bad unchoke 173 | # 12 - got bad piece 174 | # 13 - rss 175 | # 14 - rss error 176 | # 15 - got have 177 | # 16 - got bad have 178 | # 17 - error 179 | # 18 - aggregated 180 | # 19 - disconnect 181 | # 20 - out connect 182 | # 21 - in connect 183 | # 22 - UPnP 184 | # 23 - UPnP error 185 | # 24 - NATPMP 186 | # 25 - NATPMP error 187 | # 26 - metadata finish 188 | # 27 - web UI 189 | # 28 - got bad reject 190 | # 29 - pex 191 | # 30 - peer messages 192 | # 31 - blocked connect 193 | logmask: 0 194 | 195 | #dir_request (string): 196 | # Default value: "". Directory where maintenance request files will be recognized, loaded, and deleted. 197 | # If the empty string, maintenance request handling is disabled. 198 | # 199 | # Your software running on your device can create the following files in this directory in order to request the following maintenance procedures. 200 | # 201 | # If the file c.utmr is created in or moved into this directory, 202 | # the credentials necessary to access the µTorrent HTTP interface will be reset to username admin and a blank password. 203 | # 204 | # If the file wipl.utmr is created in or moved into this directory, 205 | # the IP restriction list that limits the IPs that can use the µTorrent HTTP interface is cleared, 206 | # so that there will be no restrictions on IP address. 207 | # 208 | # If the file rcf.utmr is created in or moved into this directory, 209 | # the server will reload the configuration file. If you always use this method to request a configuration file reload, 210 | # you can safely change the value of this setting while the server is running. 211 | 212 | #ut_webui_dir (string): 213 | # Default value: "". Directory where the web UI file archive webui.zip is stored, 214 | # or which contains a webui subdirectory within which the unarchived web UI files are stored. 215 | # It can be an absolute path or set relative to the current directory. 216 | ut_webui_dir: 217 | 218 | #finish_cmd (string), state_cmd (string): 219 | # Default value: "". If defined, 220 | # finish_cmd is a command that will be executed upon completion of each torrent. 221 | # state_cmd is a command that will be executed when a torrent changes state. 222 | # The command is run asynchronously as the same user that runs the server process. 223 | # 224 | # The server permits substitutions in the command text as follows: 225 | # 226 | # %F Name of downloaded data file (for single-file torrents) 227 | # %D directory where torrent data files are saved 228 | # %N torrent title 229 | # %S torrent state 230 | # %P previous state of torrent 231 | # %L label associated with torrent 232 | # %T tracker 233 | # %M status message 234 | # %I hex-encoded info-hash 235 | # 236 | # State (%S) and previous state (%P) are integers that have the following values: 237 | # 238 | # 1 (error) 239 | # 2 (checked) 240 | # 3 (paused) 241 | # 4 (super seeding) 242 | # 5 (seeding) 243 | # 6 (downloading) 244 | # 7 (super seeding (forced)) 245 | # 8 (seeding (forced)) 246 | # 9 (downloading (forced)) 247 | # 10 (queued seed) 248 | # 11 (finished) 249 | # 12 (queued) 250 | # 13 (stopped) 251 | finish_cmd: 252 | state_cmd: 253 | -------------------------------------------------------------------------------- /src/L3MON_DEMO.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/L3MON_DEMO.gif -------------------------------------------------------------------------------- /src/aria2RpcConfigSetup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/aria2RpcConfigSetup.gif -------------------------------------------------------------------------------- /src/aria2cli.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/aria2cli.png -------------------------------------------------------------------------------- /src/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/cover.png -------------------------------------------------------------------------------- /src/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/preview.gif -------------------------------------------------------------------------------- /src/rclone_config_create.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/rclone_config_create.gif -------------------------------------------------------------------------------- /src/spotify-downloader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/spotify-downloader.png -------------------------------------------------------------------------------- /src/sshPreview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/sshPreview.gif -------------------------------------------------------------------------------- /src/zip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beiona/Google-Colab-CloudTorrent/9528113e87bd79584521d0eb4286715e48a578fb/src/zip.png -------------------------------------------------------------------------------- /update.xml: -------------------------------------------------------------------------------- 1 | 2 | 1.3.0 3 | is now available! 4 | 5 | --------------------------------------------------------------------------------