├── .gitattributes ├── LICENSE ├── README.md └── CoLab_Torrent_Downloader_Pro.ipynb /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 akhi07rx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![maintenance-status](https://img.shields.io/badge/maintenance-actively--developed-brightgreen.svg) 2 | 3 | # CoLab-Torrent-Downloader-Pro 4 | 5 | This code allows you to download torrents directly to your Google Drive using Google Colab. 6 | 7 | ## Features 8 | 9 | - Download torrents from magnet links 10 | - Save downloaded files to a specified location on Google Drive 11 | - Display a progress bar and information about the downloaded file 12 | - Prompt the user to enter the magnet link or exit 13 | - Handle incorrect inputs and display error messages 14 | 15 | ## Prerequisites 16 | 17 | - A Google account with access to Google Drive and Google Colab 18 | - A magnet link for the torrent you want to download 19 | 20 | - Python 3.x 21 | - libtorrent 22 | 23 | ## Installation 24 | 25 | 1. Install the required libraries by running `!pip install libtorrent-python google-colab`. 26 | 27 | 2. Mount your Google Drive by running `from google.colab import drive; drive.mount('/content/drive')` and following the instructions. 28 | 29 | 3. Set the `save_path` variable in the script to the desired location on your Google Drive where you want to save the downloaded files. 30 | 31 | ## How to Use 32 | 33 | 1. Run the script. 34 | 35 | 2. Select an option from the main menu: 36 | 37 | - Enter Magnet link: Enter a magnet link to download a torrent. 38 | - Upload Torrent file: Upload a torrent file to download a torrent. 39 | - File Options: View file details such as "File Name," "Extension," "File Size," and "File Link" (which displays the downloaded magnet link). 40 | - Exit: Exit the program. 41 | 42 | 3. If you selected "Enter Magnet link" or "Upload Torrent file," follow the prompts to enter a magnet link or upload a torrent file. 43 | 44 | 4. The script will start downloading the torrent and display a progress bar. 45 | 46 | 5. After the download is complete, you can view file details by selecting "File Options" from the main menu. 47 | 48 | 6. When you are finished, select "Exit" from the main menu to exit the program. 49 | 50 | ## Code Components 51 | 52 | The code consists of several components: 53 | 54 | - Importing necessary libraries: `libtorrent`, `time`, `re`, `os`, `pickle`, `google.colab.drive`, `google.colab.files`, and `tqdm`. 55 | - Mounting Google Drive and setting up session parameters. 56 | - Defining regular expression pattern for validating magnet links. 57 | - Loading resume data from previous sessions. 58 | - Displaying main menu and handling user input. 59 | - Downloading torrents using magnet links or torrent files. 60 | - Displaying progress bar while downloading. 61 | - Saving resume data for future sessions. 62 | - Displaying file options menu and showing file details. 63 | 64 | ## Acknowledgments 65 | 66 | This project was inspired by various open-source torrent downloader projects. 67 | 68 | This code was developed with the help of online resources and examples. Special thanks to the developers of the `libtorrent`, `google.colab`, and `tqdm` libraries for their contributions. 69 | 70 | ## License 71 | 72 | This project is licensed under the MIT License. 73 | 74 | ## Disclaimer 75 | 76 | Please note that downloading and sharing copyrighted material without permission is illegal in many countries. Make sure you have the right to download and share the content before using this code. 77 | -------------------------------------------------------------------------------- /CoLab_Torrent_Downloader_Pro.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "attachments": {}, 5 | "cell_type": "markdown", 6 | "metadata": { 7 | "colab_type": "text", 8 | "id": "view-in-github" 9 | }, 10 | "source": [ 11 | "\"Open" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": null, 17 | "metadata": { 18 | "id": "dd7bpR_L_Z3F" 19 | }, 20 | "outputs": [], 21 | "source": [ 22 | "!apt install python3-libtorrent\n" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": null, 28 | "metadata": { 29 | "id": "74Slmak1_3JQ" 30 | }, 31 | "outputs": [], 32 | "source": [ 33 | "!python -m pip install --upgrade pip setuptools wheel\n", 34 | "!python -m pip install lbry-libtorrent" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "metadata": { 41 | "id": "n4DIwBT4_VWS" 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "import libtorrent as lt\n", 46 | "import time\n", 47 | "import re\n", 48 | "import os\n", 49 | "import pickle\n", 50 | "from google.colab import drive, files\n", 51 | "from tqdm import tqdm\n", 52 | "import patoolib\n", 53 | "from pathlib import Path\n", 54 | "\n", 55 | "drive.mount('/content/drive')\n", 56 | "\n", 57 | "ses = lt.session()\n", 58 | "ses.listen_on(6881, 6891)\n", 59 | "\n", 60 | "save_path = '/content/drive/MyDrive/Torrent Downloads/'\n", 61 | "\n", 62 | "params = {\n", 63 | " 'save_path': save_path,\n", 64 | " 'storage_mode': lt.storage_mode_t.storage_mode_sparse,\n", 65 | "}\n", 66 | "\n", 67 | "magnet_link_pattern = r'^magnet:\\?xt=urn:btih:[a-zA-Z0-9]*'\n", 68 | "\n", 69 | "resume_data_file = os.path.join(save_path, 'resume_data.pickle')\n", 70 | "\n", 71 | "if os.path.exists(resume_data_file):\n", 72 | " with open(resume_data_file, 'rb') as f:\n", 73 | " resume_data = pickle.load(f)\n", 74 | " for data in resume_data:\n", 75 | " ses.add_torrent(data)\n", 76 | "\n", 77 | "while True:\n", 78 | " print(\"\\nMenu:\")\n", 79 | " print(\"1. Enter Magnet link: \")\n", 80 | " print(\"2. Upload Torrent file: \")\n", 81 | " print(\"3. File Options\")\n", 82 | " print(\"4. Exit\")\n", 83 | "\n", 84 | " choice = input(\"Select an option (1, 2, 3 or 4): \")\n", 85 | "\n", 86 | " if choice == '1':\n", 87 | " print()\n", 88 | " link = input(\"Enter the magnet link: \")\n", 89 | " if re.match(magnet_link_pattern, link):\n", 90 | " handle = lt.add_magnet_uri(ses, link, params)\n", 91 | " else:\n", 92 | " print(\"Invalid magnet link format. Please try again.\")\n", 93 | " continue\n", 94 | " elif choice == '2':\n", 95 | " uploaded_files = files.upload()\n", 96 | " if len(uploaded_files) == 0:\n", 97 | " print(\"No files uploaded. Please try again.\")\n", 98 | " continue\n", 99 | "\n", 100 | " torrent_file_path = list(uploaded_files.values())[0]\n", 101 | "\n", 102 | " try:\n", 103 | " handle = ses.add_torrent({'ti': lt.torrent_info(torrent_file_path), 'save_path': save_path})\n", 104 | " except Exception as e:\n", 105 | " print(f\"Error: {e}\")\n", 106 | " continue\n", 107 | " elif choice == '3':\n", 108 | " if 'handle' in locals():\n", 109 | " while True:\n", 110 | " print(\"\\nFile Options:\")\n", 111 | " print(\"1. Show File Details\")\n", 112 | " print(\"2. Zip Manager\")\n", 113 | " print(\"3. Exit to Main Menu\")\n", 114 | "\n", 115 | " file_choice = input(\"Select an option (1, 2 or 3): \")\n", 116 | "\n", 117 | " if file_choice == '1':\n", 118 | " for i in range(torrent_info.num_files()):\n", 119 | " file_path = os.path.join(save_path, torrent_info.files().file_path(i))\n", 120 | " if os.path.exists(file_path):\n", 121 | " file_size = os.path.getsize(file_path)\n", 122 | " file_size_mb = file_size / (1024 ** 2)\n", 123 | " file_size_gb = file_size / (1024 ** 3)\n", 124 | " file_size_str = f\"{file_size_mb:.2f} MB / {file_size_gb:.2f} GB\"\n", 125 | " print(f\"\\nFile name: {torrent_info.files().file_path(i)}\")\n", 126 | " print(f\"File size: {file_size_str}\")\n", 127 | " print(f\"File link: {link}\")\n", 128 | " elif file_choice == '2':\n", 129 | " while True:\n", 130 | " print(\"\\nZip Manager:\")\n", 131 | " print(\"1. Extract ZIP archive\")\n", 132 | " print(\"2. Create ZIP archive\")\n", 133 | " print(\"3. Exit to File Options\\n\")\n", 134 | "\n", 135 | " zip_choice = input(\"Select an option (1, 2 or 3): \")\n", 136 | "\n", 137 | " if zip_choice == '1':\n", 138 | " zip_file_path = input(\"\\nEnter the path of the ZIP archive to extract: \")\n", 139 | " extract_dir = input(\"Enter the directory where the archive should be extracted: \")\n", 140 | " try:\n", 141 | " patoolib.extract_archive(zip_file_path, outdir=extract_dir)\n", 142 | " print(f\"\\nZIP archive extracted to {extract_dir}\")\n", 143 | " except Exception as e:\n", 144 | " print(f\"\\nError: {e}\")\n", 145 | " elif zip_choice == '2':\n", 146 | " # Get a list of all files and directories in the specified path\n", 147 | " files_and_dirs = [f for f in os.listdir(save_path)]\n", 148 | " \n", 149 | " # Display all files and directories in a numbered fashion\n", 150 | " for i, f in enumerate(files_and_dirs):\n", 151 | " print(f\"{i+1}. {f}\")\n", 152 | "\n", 153 | " # Get user input for the indices of the files or directories to zip\n", 154 | " files_to_zip_indices = input(\"\\nEnter the numbers of the files or directories to add to the ZIP archive (separated by commas): \").split(',')\n", 155 | " files_to_zip_indices = [int(i)-1 for i in files_to_zip_indices]\n", 156 | " \n", 157 | " # Get the list of files or directories to zip\n", 158 | " files_to_zip = [files_and_dirs[i] for i in files_to_zip_indices]\n", 159 | " \n", 160 | " # Get user input for the name of the ZIP archive\n", 161 | " zip_file_name = input(\"Enter the name of the ZIP archive to create: \")\n", 162 | " \n", 163 | " # Create a list of file paths to add to the ZIP archive\n", 164 | " file_paths = []\n", 165 | " for file_or_dir in files_to_zip:\n", 166 | " file_or_dir_path = os.path.join(save_path, file_or_dir)\n", 167 | " if os.path.isfile(file_or_dir_path):\n", 168 | " file_paths.append(file_or_dir_path)\n", 169 | " elif os.path.isdir(file_or_dir_path):\n", 170 | " for root, dirs, files in os.walk(file_or_dir_path):\n", 171 | " for file in files:\n", 172 | " file_path = os.path.join(root, file)\n", 173 | " file_paths.append(file_path)\n", 174 | " \n", 175 | " # Create the ZIP archive\n", 176 | " try:\n", 177 | " patoolib.create_archive(zip_file_name, file_paths)\n", 178 | " print(f\"\\nZIP archive created: {zip_file_name}\")\n", 179 | " except Exception as e:\n", 180 | " print(f\"\\nError: {e}\")\n", 181 | " elif zip_choice == '3':\n", 182 | " break\n", 183 | " else:\n", 184 | " print(\"Invalid choice. Please select a valid option.\")\n", 185 | " continue\n", 186 | " elif file_choice == '3':\n", 187 | " break\n", 188 | " else:\n", 189 | " print(\"Invalid choice. Please select a valid option.\")\n", 190 | " continue\n", 191 | " else:\n", 192 | " print(\"\\nNo file has been downloaded yet.\")\n", 193 | " continue\n", 194 | " elif choice == '4':\n", 195 | " print(\"\\nExiting the program.\")\n", 196 | " break\n", 197 | " else:\n", 198 | " print(\"Invalid choice. Please select a valid option.\")\n", 199 | " continue\n", 200 | "\n", 201 | " if choice == '1' or choice == '2':\n", 202 | " print(\"\\nDownloading Metadata...\")\n", 203 | " while not handle.has_metadata():\n", 204 | " time.sleep(1)\n", 205 | " print(\"Got Metadata, Starting Torrent Download...\")\n", 206 | "\n", 207 | " torrent_info = handle.get_torrent_info()\n", 208 | " \n", 209 | " for i in range(torrent_info.num_files()):\n", 210 | " handle.file_priority(i, 1)\n", 211 | "\n", 212 | " file_size = torrent_info.total_size()\n", 213 | " file_size_mb = file_size / (1024 ** 2)\n", 214 | " file_size_gb = file_size / (1024 ** 3)\n", 215 | " file_size_str = f\"{file_size_mb:.2f} MB / {file_size_gb:.2f} GB\"\n", 216 | " print(f\"File size: {file_size_str}\")\n", 217 | "\n", 218 | " progress_bar = tqdm(total=file_size, unit='B', unit_scale=True, leave=True)\n", 219 | "\n", 220 | " start_time = time.time()\n", 221 | "\n", 222 | " while handle.status().state != lt.torrent_status.seeding:\n", 223 | " s = handle.status()\n", 224 | " state_str = ['queued', 'checking', 'downloading metadata', 'downloading', 'finished', 'seeding', 'allocating', 'checking fastresume']\n", 225 | " progress_bar.set_description(state_str[min(s.state, len(state_str)-1)])\n", 226 | " progress_bar.update(s.total_done - progress_bar.n)\n", 227 | " time.sleep(1)\n", 228 | "\n", 229 | " progress_bar.close()\n", 230 | "\n", 231 | " end_time = time.time()\n", 232 | " total_time_seconds = end_time - start_time\n", 233 | " total_time_minutes = total_time_seconds / 60\n", 234 | "\n", 235 | " num_files = torrent_info.num_files()\n", 236 | "\n", 237 | " print(f\"\\nFile name: {torrent_info.name()}\")\n", 238 | " print(f\"File size: {file_size_str}\")\n", 239 | " print(f\"Total Time: {total_time_seconds:.2f} seconds / {total_time_minutes:.2f} minutes\")\n", 240 | " print(f\"Number of files: {num_files}\")\n", 241 | " print(f\"Saved location: {save_path}\")\n", 242 | "\n", 243 | "# save resume data\n", 244 | "resume_data = []\n", 245 | "for handle in ses.get_torrents():\n", 246 | " data = handle.save_resume_data()\n", 247 | " if data:\n", 248 | " resume_data.append({'resume_data': data, 'ti': handle.get_torrent_info(), 'save_path': save_path})\n", 249 | "with open(resume_data_file, 'wb') as f:\n", 250 | " pickle.dump(resume_data, f)\n", 251 | "\n", 252 | "\n", 253 | "#31" 254 | ] 255 | } 256 | ], 257 | "metadata": { 258 | "colab": { 259 | "include_colab_link": true, 260 | "provenance": [] 261 | }, 262 | "kernelspec": { 263 | "display_name": "Python 3", 264 | "name": "python3" 265 | }, 266 | "language_info": { 267 | "name": "python" 268 | } 269 | }, 270 | "nbformat": 4, 271 | "nbformat_minor": 0 272 | } 273 | --------------------------------------------------------------------------------