├── Master-Colab.ipynb
└── Master_Colab_Notebook_Working_&_Updated_(March_2020).ipynb
/Master_Colab_Notebook_Working_&_Updated_(March_2020).ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "nbformat": 4,
3 | "nbformat_minor": 0,
4 | "metadata": {
5 | "colab": {
6 | "name": "Master Colab Notebook - Working & Updated (March 2020)",
7 | "provenance": [],
8 | "collapsed_sections": [
9 | "zRTgBdCpBWMh",
10 | "cOUZEXihsqCD",
11 | "bNAroQWy6hL3",
12 | "wZMZjX127rmx",
13 | "4E-uzYrv5o0B",
14 | "ZVIyGBSmjlOY",
15 | "AAOkoLYa1nQb",
16 | "smfdosUWghxD",
17 | "Nx9ud5luiyJY",
18 | "8YFON0D4mVdr",
19 | "StT2bKf2WmKj",
20 | "mtIWnZ60Sczn",
21 | "jWNiE-RGECHM",
22 | "MbJ_88vSD-K2",
23 | "yTPpo294F0U8",
24 | "n3MWoStHEnJx",
25 | "DYreGU9NvCdk",
26 | "t0eVljW0O0CG",
27 | "ukxnQC4c0nuR",
28 | "EFOqhHG6hOVH",
29 | "KgNPvGccgwd8",
30 | "RDHuIkoi6l9a",
31 | "NQ0TxfKeghR8",
32 | "FpJXJiRl6-gK",
33 | "2f-THZmDoOaY",
34 | "MSUasbRUDP3B",
35 | "0xI8WiUPji3k",
36 | "Nl4RbJbX0-a4",
37 | "QlsUJhNwyeV3",
38 | "cHTe9qp2E6f5",
39 | "kAdRu4gm5k8v"
40 | ],
41 | "include_colab_link": true
42 | },
43 | "kernelspec": {
44 | "name": "python3",
45 | "display_name": "Python 3"
46 | },
47 | "accelerator": "TPU"
48 | },
49 | "cells": [
50 | {
51 | "cell_type": "markdown",
52 | "metadata": {
53 | "id": "view-in-github",
54 | "colab_type": "text"
55 | },
56 | "source": [
57 | "
"
58 | ]
59 | },
60 | {
61 | "cell_type": "markdown",
62 | "metadata": {
63 | "colab_type": "text",
64 | "id": "zRTgBdCpBWMh"
65 | },
66 | "source": [
67 | "# ✦ *Quick Useful Scripts:*"
68 | ]
69 | },
70 | {
71 | "cell_type": "markdown",
72 | "metadata": {
73 | "id": "cOUZEXihsqCD",
74 | "colab_type": "text"
75 | },
76 | "source": [
77 | "## ✧ MediaInfo"
78 | ]
79 | },
80 | {
81 | "cell_type": "code",
82 | "metadata": {
83 | "id": "NTULRguzu0b0",
84 | "colab_type": "code",
85 | "cellView": "form",
86 | "colab": {}
87 | },
88 | "source": [
89 | "path = \"\" #@param {type:\"string\"}\n",
90 | "save_txt = False #@param {type:\"boolean\"}\n",
91 | "import os, uuid, re, IPython\n",
92 | "import ipywidgets as widgets\n",
93 | "import time\n",
94 | "\n",
95 | "from glob import glob\n",
96 | "from IPython.display import HTML, clear_output\n",
97 | "from google.colab import output, drive\n",
98 | "\n",
99 | "def mediainfo():\n",
100 | " display(HTML(\"
\"))\n",
101 | "# print(path.split(\"/\")[::-1][0])\n",
102 | " display(HTML(\"
\"))\n",
103 | "# media = !mediainfo \"$path\"\n",
104 | "# media = \"\\n\".join(media).replace(os.path.dirname(path)+\"/\", \"\")\n",
105 | " get_ipython().system_raw(\"\"\"mediainfo --LogFile=\"/root/.nfo\" \"$path\" \"\"\")\n",
106 | " with open('/root/.nfo', 'r') as file:\n",
107 | " media = file.read()\n",
108 | " media = media.replace(os.path.dirname(path)+\"/\", \"\")\n",
109 | " print(media)\n",
110 | " get_ipython().system_raw(\"rm -f '/root/.nfo'\")\n",
111 | " \n",
112 | " if save_txt:\n",
113 | " txt = path.rpartition('.')[0] + \".txt\"\n",
114 | " if os.path.exists(txt):\n",
115 | " get_ipython().system_raw(\"rm -f '$txt'\")\n",
116 | " !curl -s https://pastebin.com/raw/TApKLQfM -o \"$txt\"\n",
117 | " with open(txt, 'a+') as file:\n",
118 | " file.write(\"\\n\\n\")\n",
119 | " file.write(media)\n",
120 | "\n",
121 | "while not os.path.exists(\"/content/drive\"):\n",
122 | " try:\n",
123 | " drive.mount(\"/content/drive\")\n",
124 | " clear_output(wait=True)\n",
125 | " except:\n",
126 | " clear_output()\n",
127 | " \n",
128 | "if not os.path.exists(\"/usr/bin/mediainfo\"):\n",
129 | " get_ipython().system_raw(\"apt-get install mediainfo\")\n",
130 | " \n",
131 | "mediainfo()"
132 | ],
133 | "execution_count": 0,
134 | "outputs": []
135 | },
136 | {
137 | "cell_type": "markdown",
138 | "metadata": {
139 | "id": "bNAroQWy6hL3",
140 | "colab_type": "text"
141 | },
142 | "source": [
143 | "## ✧ Generate Streamable Video Links from Google Drive\n",
144 | "##### *Note: This cell will only work with links that are shared publically*"
145 | ]
146 | },
147 | {
148 | "cell_type": "code",
149 | "metadata": {
150 | "colab_type": "code",
151 | "cellView": "form",
152 | "id": "W4EXnKHuwmq0",
153 | "colab": {}
154 | },
155 | "source": [
156 | "import re\n",
157 | "\n",
158 | "shared_file_link = \"https://drive.google.com/open?id=\" #@param {type:\"string\"}\n",
159 | "result = re.search(\"[\\w-]{33}\", shared_file_link)\n",
160 | "your_api_key = \"\" #@param {type:\"string\"}\n",
161 | "drive_file_id = result.group(0)\n",
162 | "\n",
163 | "beg_url = \"https://www.googleapis.com/drive/v3/files/\"\n",
164 | "end_url = \"/?key=\" + your_api_key + \"&alt=media\"\n",
165 | "\n",
166 | "print(beg_url + drive_file_id + end_url)\n",
167 | "\n",
168 | "## *This cell will only work with links that are shared publically*"
169 | ],
170 | "execution_count": 0,
171 | "outputs": []
172 | },
173 | {
174 | "cell_type": "markdown",
175 | "metadata": {
176 | "id": "wZMZjX127rmx",
177 | "colab_type": "text"
178 | },
179 | "source": [
180 | "## ✧ Crash Colab to clear all RAM"
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "metadata": {
186 | "id": "OH3xVkwWmPYL",
187 | "colab_type": "code",
188 | "cellView": "form",
189 | "colab": {}
190 | },
191 | "source": [
192 | "#@title ← ឵឵ ឵Run this cell to crash your current Runtime if you're low on memory\n",
193 | "#@markdown After crashing, you'll have access to all the preoccupied storage\n",
194 | "some_str = ' ' * 5120000000000"
195 | ],
196 | "execution_count": 0,
197 | "outputs": []
198 | },
199 | {
200 | "cell_type": "markdown",
201 | "metadata": {
202 | "id": "4E-uzYrv5o0B",
203 | "colab_type": "text"
204 | },
205 | "source": [
206 | "# **0.** Mounting with rclone\n",
207 | "#
"
208 | ]
209 | },
210 | {
211 | "cell_type": "code",
212 | "metadata": {
213 | "id": "iroeLPFdXbif",
214 | "colab_type": "code",
215 | "cellView": "form",
216 | "colab": {}
217 | },
218 | "source": [
219 | "#@markdown
Step 1. Upload your rclone.conf
profile
\n",
220 | "#@markdown *required to mount your drive!\n",
221 | "#@markdown \n",
222 | "Setup_Time_Zone = False \n",
223 | "\n",
224 | "import os; from google.colab import files; from IPython.display import HTML, clear_output\n",
225 | "\n",
226 | "def upload_conf():\n",
227 | " try:\n",
228 | " display(HTML(\"Please upload the config file of rclone (rclone.conf) from your computer.
\"))\n",
229 | " UploadConfig = files.upload().keys()\n",
230 | " clear_output(wait=True)\n",
231 | " if len(UploadConfig) == 0:\n",
232 | " return display(HTML(\"File upload has been cancelled during upload file.
\"))\n",
233 | " elif len(UploadConfig) == 1:\n",
234 | " for fn in UploadConfig:\n",
235 | " if os.path.isfile(\"/content/\" + fn) == True:\n",
236 | " os.environ[\"rclone_conf\"] = fn\n",
237 | " !mv -f \"$rclone_conf\" /root/.rclone.conf\n",
238 | " !chmod 666 /root/.rclone.conf\n",
239 | " if Setup_Time_Zone == True:\n",
240 | " !sudo dpkg-reconfigure tzdata\n",
241 | " clear_output(wait=True)\n",
242 | " if os.path.isfile(\"/usr/bin/rclone\") == True:\n",
243 | " return display(HTML(\"Config has been changed.
\"))\n",
244 | " else:\n",
245 | " !rm -rf /content/sample_data/\n",
246 | " !curl -s https://rclone.org/install.sh | sudo bash\n",
247 | " clear_output(wait=True)\n",
248 | " return display(HTML(\"Installation has been successfully completed.
\"))\n",
249 | " else:\n",
250 | " return display(HTML(\"File upload has been failed during upload file.
\"))\n",
251 | " else:\n",
252 | " for fn in UploadConfig:\n",
253 | " os.environ[\"rclone_conf\"] = fn\n",
254 | " !rm -f \"$rclone_conf\"\n",
255 | " return display(HTML(\"Please uploading only one file at a time.
\"))\n",
256 | " except:\n",
257 | " clear_output(wait=True)\n",
258 | " return display(HTML(\"Error occurred during upload file.
\"))\n",
259 | "\n",
260 | "upload_conf()"
261 | ],
262 | "execution_count": 0,
263 | "outputs": []
264 | },
265 | {
266 | "cell_type": "code",
267 | "metadata": {
268 | "id": "mp6XoynaX4HN",
269 | "colab_type": "code",
270 | "cellView": "form",
271 | "colab": {}
272 | },
273 | "source": [
274 | "# ============================= FORM ============================= #\n",
275 | "#@markdown Step 2. Mount your Drive with rclone
\n",
276 | "#@markdown - Replace values to match the
rclone.conf
file you just uploaded
\n",
277 | "rclone_config_name = \"GDrive\" #@param {type:\"string\"}\n",
278 | "local_mount_location = \"/content/udrive/\" #@param {type:\"string\"}\n",
279 | "# ============================= FORM ============================= #\n",
280 | "import time\n",
281 | "import os\n",
282 | "\n",
283 | "# clear nohup\n",
284 | "open(\"nohup.out\", 'w').close()\n",
285 | "\n",
286 | "\n",
287 | "# unmount first\n",
288 | "\n",
289 | "!fusermount -u $local_mount_location 2>/dev/null\n",
290 | "\n",
291 | "\n",
292 | "# mount without waiting for the command to complete\n",
293 | "!mkdir $local_mount_location 2>/dev/null\n",
294 | "!nohup rclone mount $rclone_config_name: $local_mount_location --buffer-size 96M & \n",
295 | " \n",
296 | "\n",
297 | "\n",
298 | "# Show the output that was written to nohup\n",
299 | "time.sleep(3)\n",
300 | "f = open(r\"nohup.out\", \"r\")\n",
301 | "nohupText = f.read()\n",
302 | "f.close()\n",
303 | "\n",
304 | "\n",
305 | "dirs = os.listdir(local_mount_location)\n",
306 | "\n",
307 | "if len(dirs) > 0:\n",
308 | " clear_output(wait=True)\n",
309 | " print(\"Succeeded. \", str(len(dirs)), \"dirs found at\", local_mount_location)\n",
310 | "\n",
311 | "else:\n",
312 | " print(\"\\n\\nNot succeeded. No files or directories in mounted location. \\nCheck your config name and content. If the rclone command was not found, run the cell above.\\n\\n\")\n",
313 | " print(\"log:\\n\", nohupText)"
314 | ],
315 | "execution_count": 0,
316 | "outputs": []
317 | },
318 | {
319 | "cell_type": "markdown",
320 | "metadata": {
321 | "id": "ZVIyGBSmjlOY",
322 | "colab_type": "text"
323 | },
324 | "source": [
325 | "# **1**. Mounting Google Drive\n",
326 | "#
"
327 | ]
328 | },
329 | {
330 | "cell_type": "code",
331 | "metadata": {
332 | "id": "6DzJx4rdjvUQ",
333 | "colab_type": "code",
334 | "cellView": "form",
335 | "colab": {}
336 | },
337 | "source": [
338 | "#@markdown ← ឵឵Click Here to Mount your Google Drive
\n",
339 | "#@markdown (Provided by Google)
\n",
340 | "from google.colab import drive\n",
341 | "drive.mount('/content/drive')"
342 | ],
343 | "execution_count": 0,
344 | "outputs": []
345 | },
346 | {
347 | "cell_type": "code",
348 | "metadata": {
349 | "id": "IsQPA4qZD4hK",
350 | "colab_type": "code",
351 | "cellView": "form",
352 | "colab": {}
353 | },
354 | "source": [
355 | "#@markdown ← ឵឵Click Here to Force Remount your Google Drive
\n",
356 | "#@markdown (Only use if needed)
\n",
357 | "drive.mount(\"/content/drive\", force_remount=True)"
358 | ],
359 | "execution_count": 0,
360 | "outputs": []
361 | },
362 | {
363 | "cell_type": "markdown",
364 | "metadata": {
365 | "id": "AAOkoLYa1nQb",
366 | "colab_type": "text"
367 | },
368 | "source": [
369 | "# **2**. qBitTorrent\n",
370 | "# 

"
371 | ]
372 | },
373 | {
374 | "cell_type": "markdown",
375 | "metadata": {
376 | "id": "smfdosUWghxD",
377 | "colab_type": "text"
378 | },
379 | "source": [
380 | "## **A**.
\n"
381 | ]
382 | },
383 | {
384 | "cell_type": "markdown",
385 | "metadata": {
386 | "id": "0jctMTc3-rPt",
387 | "colab_type": "text"
388 | },
389 | "source": [
390 | "* You'll need your own ngrok Auth Token to use this cell. After logging in, you can find it [here](https://dashboard.ngrok.com/auth).\n",
391 | " * [Screenshot](https://yuju.pw/y/8Z3S.png) locating your ngrok Auth Token."
392 | ]
393 | },
394 | {
395 | "cell_type": "code",
396 | "metadata": {
397 | "colab_type": "code",
398 | "cellView": "form",
399 | "id": "dmAyXqzfL9yK",
400 | "colab": {}
401 | },
402 | "source": [
403 | "#@title ← ឵឵ Run This Cell for ***qBitTorrent*** *v4.1.7 Web UI*\n",
404 | "Ngrok_Token = \"\" #@param {type:\"string\"}\n",
405 | "import os, time, urllib.request, json; from IPython.display import clear_output\n",
406 | "if os.path.isfile(\"/usr/bin/qbittorrent-nox\") == False:\n",
407 | " get_ipython().system_raw(\"apt update -qq -y && yes \"\" | add-apt-repository ppa:qbittorrent-team/qbittorrent-stable\")\n",
408 | " get_ipython().system_raw(\"apt install qbittorrent-nox\")\n",
409 | " get_ipython().system_raw(\"mkdir -p -m 666 /{content/qBittorrent,root/{.qBittorrent_temp,.config/qBittorrent}} && curl -s https://pastebin.com/raw/XbthBkJU -o /root/.config/qBittorrent/qBittorrent.conf\")\n",
410 | " print(\"qBittorrent successfully installed.\")\n",
411 | " clear_output(wait=True)\n",
412 | "else:\n",
413 | " print(\"qBittorrent already installed. Skipping...\")\n",
414 | " clear_output(wait=True)\n",
415 | " !pkill qbittorrent-nox\n",
416 | " \n",
417 | "!qbittorrent-nox -d --webui-port=4444\n",
418 | "print(\"qBittorrent started \")\n",
419 | "clear_output(wait=True)\n",
420 | "\n",
421 | "if os.path.isfile(\"/usr/local/bin/ngrok\") == False:\n",
422 | " !wget -q -c -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n",
423 | " !unzip -qq -n ngrok-stable-linux-amd64.zip\n",
424 | " !mv ngrok /usr/local/bin/ngrok\n",
425 | " !rm -f /content/ngrok-stable-linux-amd64.zip\n",
426 | " print(\"ngrok successfully installed.\")\n",
427 | " clear_output(wait=True)\n",
428 | "else:\n",
429 | " print(\"ngrok already installed. Skipping... \")\n",
430 | " clear_output(wait=True)\n",
431 | " !pkill ngrok\n",
432 | " \n",
433 | "if os.path.isfile(\"/usr/bin/rclone\") == False:\n",
434 | " get_ipython().system_raw('curl https://rclone.org/install.sh | sudo bash &')\n",
435 | " print(\"Rclone successfully installed\")\n",
436 | " clear_output(wait=True)\n",
437 | "else:\n",
438 | " print(\"Rclone already installed. Skipping...\")\n",
439 | " clear_output(wait=True)\n",
440 | "\n",
441 | "get_ipython().system_raw('/usr/local/bin/ngrok authtoken $Ngrok_Token && /usr/local/bin/ngrok http 4444 &')\n",
442 | "print(\"Hold on...\")\n",
443 | "time.sleep(10)\n",
444 | "clear_output(wait=True)\n",
445 | "with urllib.request.urlopen('http://localhost:4040/api/tunnels') as response:\n",
446 | " data = json.loads(response.read().decode())\n",
447 | " host = data['tunnels'][0]['public_url'][8:]\n",
448 | " print(f'Open this link in new tab http://{host}')"
449 | ],
450 | "execution_count": 0,
451 | "outputs": []
452 | },
453 | {
454 | "cell_type": "markdown",
455 | "metadata": {
456 | "colab_type": "text",
457 | "id": "Nx9ud5luiyJY"
458 | },
459 | "source": [
460 | "## **B**.
\n",
461 | "#### (***Not Recommended***)\n"
462 | ]
463 | },
464 | {
465 | "cell_type": "code",
466 | "metadata": {
467 | "id": "aO74zstqkSsh",
468 | "colab_type": "code",
469 | "cellView": "form",
470 | "colab": {}
471 | },
472 | "source": [
473 | "#@title ← ឵឵ Run This Cell for ***qBitTorrent*** *v4.1.7 Web UI* \n",
474 | "#@markdown - Don't use the mounted Google Drive as a save path for torrent; data corruption will most likely occur.
\n",
475 | "Old_Version = False #@param {type:\"boolean\"}\n",
476 | "# ================================================================ #\n",
477 | "\n",
478 | "import os, psutil, IPython, uuid, time\n",
479 | "import ipywidgets as widgets\n",
480 | "\n",
481 | "from IPython.display import HTML, clear_output\n",
482 | "from google.colab import output\n",
483 | "\n",
484 | "class MakeButton(object):\n",
485 | " def __init__(self, title, callback):\n",
486 | " self._title = title\n",
487 | " self._callback = callback\n",
488 | " def _repr_html_(self):\n",
489 | " callback_id = 'button-' + str(uuid.uuid4())\n",
490 | " output.register_callback(callback_id, self._callback)\n",
491 | " template = \"\"\"\n",
492 | " \"\"\"\n",
498 | " html = template.format(title=self._title, callback_id=callback_id)\n",
499 | " return html\n",
500 | " \n",
501 | "def MakeLabel(description, button_style):\n",
502 | " return widgets.Button(description=description, disabled=True, button_style=button_style)\n",
503 | "\n",
504 | "def RandomGenerator():\n",
505 | " return time.strftime(\"%S\") + str(time.time()).split(\".\")[-1]\n",
506 | "\n",
507 | "def CheckProcess(process, command):\n",
508 | " for pid in psutil.pids():\n",
509 | " try:\n",
510 | " p = psutil.Process(pid)\n",
511 | " if process in p.name():\n",
512 | " for arg in p.cmdline():\n",
513 | " if command in str(arg): \n",
514 | " return True\n",
515 | " else:\n",
516 | " pass\n",
517 | " else:\n",
518 | " pass\n",
519 | " except:\n",
520 | " continue\n",
521 | " \n",
522 | "def AutoSSH(name,port):\n",
523 | " get_ipython().system_raw(\"autossh -l \" + name + \" -M 0 -fNT -o 'StrictHostKeyChecking=no' -o 'ServerAliveInterval 300' -o 'ServerAliveCountMax 30' -R 80:localhost:\" + port + \" ssh.localhost.run &\")\n",
524 | " get_ipython().system_raw(\"autossh -M 0 -fNT -o 'StrictHostKeyChecking=no' -o 'ServerAliveInterval 300' -o 'ServerAliveCountMax 30' -R \" + name + \":80:localhost:\" + port + \" serveo.net &\")\n",
525 | "\n",
526 | "def Start_Server():\n",
527 | " if CheckProcess(\"qbittorrent-nox\", \"\") != True:\n",
528 | " get_ipython().system_raw(\"qbittorrent-nox -d --webui-port=6006\")\n",
529 | " if CheckProcess(\"autossh\", \"qb\" + Random_Number) != True:\n",
530 | " AutoSSH(\"qb\" + Random_Number, \"6006\")\n",
531 | "\n",
532 | "try:\n",
533 | " try:\n",
534 | " Random_Number\n",
535 | " except NameError:\n",
536 | " display(MakeLabel(\"Installing in Progress\", \"warning\"))\n",
537 | " Random_Number = RandomGenerator()\n",
538 | " get_ipython().system_raw(\"rm -rf /content/sample_data/ &\")\n",
539 | " if os.path.isfile(\"/usr/bin/qbittorrent-nox\") == False:\n",
540 | " get_ipython().system_raw(\"apt update -qq -y && yes \"\" | add-apt-repository ppa:qbittorrent-team/qbittorrent-stable\")\n",
541 | " if Old_Version == True:\n",
542 | " get_ipython().system_raw(\"apt install qbittorrent-nox=4.0.3-1 -qq -y\")\n",
543 | " else:\n",
544 | " get_ipython().system_raw(\"apt install qbittorrent-nox -qq -y\")\n",
545 | " get_ipython().system_raw(\"mkdir -p -m 666 /{content/qBittorrent,root/{.qBittorrent_temp,.config/qBittorrent}} && wget -q https://minormole.github.io/RcloneLab/res/qbittorrent/qBittorrent.conf -O /root/.config/qBittorrent/qBittorrent.conf\")\n",
546 | " if os.path.isfile(\"/usr/bin/autossh\") == False:\n",
547 | " get_ipython().system_raw(\"apt install autossh -qq -y\")\n",
548 | " Start_Server()\n",
549 | " clear_output(wait=True)\n",
550 | " display(MakeLabel(\"✔ Successfully\", \"success\"), MakeButton(\"Recheck\", Start_Server), HTML(\"qBittorrent
\"))\n",
553 | "except:\n",
554 | " clear_output(wait=True)\n",
555 | " display(MakeLabel(\"✘ Unsuccessfully\", \"danger\"))"
556 | ],
557 | "execution_count": 0,
558 | "outputs": []
559 | },
560 | {
561 | "cell_type": "markdown",
562 | "metadata": {
563 | "id": "8YFON0D4mVdr",
564 | "colab_type": "text"
565 | },
566 | "source": [
567 | "# **3**. JDownloader\n",
568 | "#
"
569 | ]
570 | },
571 | {
572 | "cell_type": "code",
573 | "metadata": {
574 | "id": "eyTydVIrm2Ms",
575 | "colab_type": "code",
576 | "cellView": "form",
577 | "colab": {}
578 | },
579 | "source": [
580 | "#@markdown ← ឵឵ Click Here to Install JDownloader\n",
581 | "\n",
582 | "import os, uuid, re, IPython\n",
583 | "import ipywidgets as widgets\n",
584 | "\n",
585 | "from glob import glob\n",
586 | "from IPython.display import HTML, clear_output\n",
587 | "from google.colab import output\n",
588 | "\n",
589 | "Email = widgets.Text(placeholder=\"*Required\", description=\"Email:\")\n",
590 | "Password = widgets.Text(placeholder=\"*Required\", description=\"Password:\")\n",
591 | "Device = widgets.Text(placeholder=\"Optional\", description=\"Name:\")\n",
592 | "SavePath = widgets.Dropdown(value=\"/content\", options=[\"/content\", \"/content/Downloads\"], description=\"Save Path:\")\n",
593 | "\n",
594 | "class MakeButton(object):\n",
595 | " def __init__(self, title, callback, style):\n",
596 | " self._title = title\n",
597 | " self._callback = callback\n",
598 | " self._style = style\n",
599 | " def _repr_html_(self):\n",
600 | " callback_id = 'button-' + str(uuid.uuid4())\n",
601 | " output.register_callback(callback_id, self._callback)\n",
602 | " if self._style != \"\":\n",
603 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button mod-\" + self._style\n",
604 | " else:\n",
605 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button\"\n",
606 | " template = \"\"\"\n",
607 | " \"\"\"\n",
613 | " html = template.format(title=self._title, callback_id=callback_id, style_html=style_html)\n",
614 | " return html\n",
615 | " \n",
616 | "def MakeLabel(description, button_style):\n",
617 | " return widgets.Button(description=description, disabled=True, button_style=button_style)\n",
618 | "\n",
619 | "def RefreshPath():\n",
620 | " if os.path.exists(\"/content/drive/\"):\n",
621 | " if os.path.exists(\"/content/drive/Shared drives/\"):\n",
622 | " SavePath.options = [\"/content\", \"/content/Downloads\", \"/content/drive/My Drive\"] + glob(\"/content/drive/Shared drives/*\")\n",
623 | " else:\n",
624 | " SavePath.options = [\"/content\", \"/content/Downloads\", \"/content/drive/My Drive\"]\n",
625 | " else:\n",
626 | " SavePath.options = [\"/content\", \"/content/Downloads\"]\n",
627 | "\n",
628 | "def LoginForm():\n",
629 | " clear_output()\n",
630 | " Email.value = \"\"\n",
631 | " Password.value = \"\"\n",
632 | " Device.value = \"\"\n",
633 | " RefreshPath()\n",
634 | " display(HTML(\"If you don't have an account yet, please register here.
\"), HTML(\"
\"), Email, Password, Device, SavePath)\n",
635 | " if not os.path.exists(\"/content/drive/\"):\n",
636 | " display(HTML(\"*If you want to save in Google Drive please run the cell below.\"))\n",
637 | " display(HTML(\"
\"), MakeButton(\"Login\", CheckLogin, \"info\"))\n",
638 | " if os.path.isfile(\"/root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json\"):\n",
639 | " display(MakeButton(\"Cancel\", Show, \"danger\"))\n",
640 | " \n",
641 | "def RestartForm():\n",
642 | " clear_output()\n",
643 | " display(MakeLabel(\"Restart Confirm?\", \"\"), MakeButton(\"Confirm\", Restart, \"danger\"), MakeButton(\"Cancel\", Show, \"warning\"))\n",
644 | " \n",
645 | "def ExitForm():\n",
646 | " clear_output()\n",
647 | " display(MakeLabel(\"Exit Confirm?\", \"\"), MakeButton(\"Confirm\", Exit, \"danger\"), MakeButton(\"Cancel\", Show, \"warning\"))\n",
648 | "\n",
649 | "def CheckLogin():\n",
650 | " try:\n",
651 | " if not Email.value.strip():\n",
652 | " ERROR = \"Email field is empty.\"\n",
653 | " THROW_ERROR\n",
654 | " if not \"@\" in Email.value and not \".\" in Email.value:\n",
655 | " ERROR = \"Email is an incorrect format.\"\n",
656 | " THROW_ERROR\n",
657 | " if not Password.value.strip():\n",
658 | " ERROR = \"Password field is empty.\"\n",
659 | " THROW_ERROR\n",
660 | " if not bool(re.match(\"^[a-zA-Z0-9]+$\", Device.value)) and Device.value.strip():\n",
661 | " ERROR = \"Only alphanumeric are allowed for the device name.\"\n",
662 | " THROW_ERROR\n",
663 | " Login()\n",
664 | " except:\n",
665 | " print(ERROR)\n",
666 | "\n",
667 | "def Login():\n",
668 | " clear_output()\n",
669 | " if SavePath.value == \"/content\":\n",
670 | " get_ipython().system_raw(\"echo '{\\\"defaultdownloadfolder\\\" : \\\"/content\\\"}' > /root/.JDownloader/cfg/org.jdownloader.settings.GeneralSettings.json\")\n",
671 | " elif SavePath.value == \"/content/Downloads\":\n",
672 | " get_ipython().system_raw(\"mkdir -p -m 666 /content/Downloads\")\n",
673 | " get_ipython().system_raw(\"echo '{\\\"defaultdownloadfolder\\\" : \\\"/content/Downloads\\\"}' > /root/.JDownloader/cfg/org.jdownloader.settings.GeneralSettings.json\")\n",
674 | " else:\n",
675 | " get_ipython().system_raw(\"echo '{\\\"defaultdownloadfolder\\\" : \\\"\" + SavePath.value + \"\\\"}' > /root/.JDownloader/cfg/org.jdownloader.settings.GeneralSettings.json\")\n",
676 | " if Device.value.strip() == \"\":\n",
677 | " Device.value = Email.value\n",
678 | " get_ipython().system_raw(\"pkill -9 -e -f java\")\n",
679 | " get_ipython().system_raw(\"echo '{\\\"email\\\" : \\\"'\" + Email.value + \"'\\\", \\\"password\\\" : \\\"'\" + Password.value + \"'\\\", \\\"devicename\\\" : \\\"'\" + Device.value + \"'\\\", \\\"directconnectmode\\\" : \\\"LAN\\\"}' > /root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json\")\n",
680 | " get_ipython().system_raw(\"java -jar /root/.JDownloader/JDownloader.jar -norestart -noerr -r &\")\n",
681 | " Show()\n",
682 | "\n",
683 | "def Restart():\n",
684 | " get_ipython().system_raw(\"pkill -9 -e -f java\")\n",
685 | " get_ipython().system_raw(\"java -jar /root/.JDownloader/JDownloader.jar -norestart -noerr -r &\")\n",
686 | " Show()\n",
687 | " \n",
688 | "def Exit():\n",
689 | " get_ipython().system_raw(\"pkill -9 -e -f java\")\n",
690 | " clear_output()\n",
691 | " display(MakeButton(\"Start\", Restart, \"info\"))\n",
692 | " \n",
693 | "def Show():\n",
694 | " clear_output()\n",
695 | " display(MakeLabel(\"Control Panel\", \"\"), HTML(\"You can login to the WebUI by clicking here.
\"), HTML(\"If the server didn't showup in 30 sec. please re-login.
\"), HTML(\"
\"), MakeButton(\"Re-Login\", LoginForm, \"info\"), MakeButton(\"Restart\", RestartForm, \"warning\"), MakeButton(\"Exit\", ExitForm, \"danger\"))\n",
696 | " \n",
697 | " \n",
698 | "if not os.path.isfile(\"/root/.JDownloader/JDownloader.jar\"):\n",
699 | " clear_output()\n",
700 | " display(MakeLabel(\"Installing in Progress\", \"warning\"))\n",
701 | " get_ipython().system_raw(\"rm -rf /content/sample_data/ && apt install openjdk-8-jre-headless -qq -y && mkdir -p -m 666 /root/.JDownloader && wget -q http://installer.jdownloader.org/JDownloader.jar -O /root/.JDownloader/JDownloader.jar && java -jar /root/.JDownloader/JDownloader.jar -norestart -h\")\n",
702 | " LoginForm()\n",
703 | "elif not os.path.isfile(\"/root/.JDownloader/cfg/org.jdownloader.api.myjdownloader.MyJDownloaderSettings.json\"):\n",
704 | " LoginForm()\n",
705 | "else: \n",
706 | " Show()"
707 | ],
708 | "execution_count": 0,
709 | "outputs": []
710 | },
711 | {
712 | "cell_type": "markdown",
713 | "metadata": {
714 | "id": "StT2bKf2WmKj",
715 | "colab_type": "text"
716 | },
717 | "source": [
718 | "# **4**. wget\n",
719 | "#
\n"
720 | ]
721 | },
722 | {
723 | "cell_type": "code",
724 | "metadata": {
725 | "id": "_NiTOoCg-hLp",
726 | "colab_type": "code",
727 | "cellView": "form",
728 | "colab": {}
729 | },
730 | "source": [
731 | "#@title ← Run to Download a DDL File\n",
732 | "#@markdown Example URL: https://files.catbox.moe/archive.zip\n",
733 | "direct_URL = \"\" #@param {type:\"string\"}\n",
734 | "output_dir = \"/content\" #@param {type:\"string\"}\n",
735 | "\n",
736 | "!wget \"$Direct_URL\" \"$output_dir\""
737 | ],
738 | "execution_count": 0,
739 | "outputs": []
740 | },
741 | {
742 | "cell_type": "markdown",
743 | "metadata": {
744 | "id": "mtIWnZ60Sczn",
745 | "colab_type": "text"
746 | },
747 | "source": [
748 | "# **5**. folderclone\n",
749 | "\n",
750 | "#
\n",
751 | "\n"
752 | ]
753 | },
754 | {
755 | "cell_type": "markdown",
756 | "metadata": {
757 | "id": "jWNiE-RGECHM",
758 | "colab_type": "text"
759 | },
760 | "source": [
761 | "### **Step 1.** Installing Required modules"
762 | ]
763 | },
764 | {
765 | "cell_type": "code",
766 | "metadata": {
767 | "id": "12dTZfUQEN8b",
768 | "colab_type": "code",
769 | "cellView": "form",
770 | "colab": {}
771 | },
772 | "source": [
773 | "#@markdown ← Run this cell to install all required modules
\n",
774 | "!pip3 install folderclone"
775 | ],
776 | "execution_count": 0,
777 | "outputs": []
778 | },
779 | {
780 | "cell_type": "markdown",
781 | "metadata": {
782 | "id": "MbJ_88vSD-K2",
783 | "colab_type": "text"
784 | },
785 | "source": [
786 | "### **Step 2.** Pulling your repo from GitHub\n",
787 | "- *Remove* \"https://
\" *from Repo link*"
788 | ]
789 | },
790 | {
791 | "cell_type": "code",
792 | "metadata": {
793 | "id": "h5kQ5bxsDNiX",
794 | "colab_type": "code",
795 | "cellView": "form",
796 | "colab": {}
797 | },
798 | "source": [
799 | "#@markdown ← Click here download your private repo
\n",
800 | "import os\n",
801 | "username = \"\" #@param {type:\"string\"}\n",
802 | "Password = \"\"#@param {type:\"string\"}\n",
803 | "Repolink = \"github.com/Sarah/MFCBPDEMO\"#@param {type:\"string\"}\n",
804 | "!git clone https://\"$username\":\"$Password\"@\"$Repolink\".git"
805 | ],
806 | "execution_count": 0,
807 | "outputs": []
808 | },
809 | {
810 | "cell_type": "markdown",
811 | "metadata": {
812 | "id": "yTPpo294F0U8",
813 | "colab_type": "text"
814 | },
815 | "source": [
816 | "### **Step 3.** Adding All SAs to Google Group"
817 | ]
818 | },
819 | {
820 | "cell_type": "markdown",
821 | "metadata": {
822 | "id": "m2b0lgo8Pc8C",
823 | "colab_type": "text"
824 | },
825 | "source": [
826 | "- Add your service accounts emails to one collective Google Group (limit 100 per day)\n",
827 | "- Share your `@googlegroups.com` email with the Source TD, and the Destination TD\n",
828 | "\n",
829 | "Important:
\n",
830 | " ✧ ឵After completing this step, you can skip it in the future!"
831 | ]
832 | },
833 | {
834 | "cell_type": "markdown",
835 | "metadata": {
836 | "id": "n3MWoStHEnJx",
837 | "colab_type": "text"
838 | },
839 | "source": [
840 | "### **Step 4.** Running folderclone\n"
841 | ]
842 | },
843 | {
844 | "cell_type": "code",
845 | "metadata": {
846 | "colab_type": "code",
847 | "cellView": "form",
848 | "id": "nLyWJmQXO4vr",
849 | "colab": {}
850 | },
851 | "source": [
852 | "#@title ← Run to clone all folders + files from src
to dest
\n",
853 | "#@markdown Paste only the Folder IDs for these values:\n",
854 | "src = \"\" #@param {type:\"string\"}\n",
855 | "dest = \"\" #@param {type:\"string\"}\n",
856 | "accountspath = \"/content/folderclone/accounts\"#@param {type:\"string\"}\n",
857 | "!multifolderclone -s \"$src\" -d \"$dest\" --path \"$accountspath\""
858 | ],
859 | "execution_count": 0,
860 | "outputs": []
861 | },
862 | {
863 | "cell_type": "markdown",
864 | "metadata": {
865 | "id": "505daA1YPSdW",
866 | "colab_type": "text"
867 | },
868 | "source": [
869 | "- Add the Source Folder ID and then the Destination Folder ID\n",
870 | "- Note: ***Your source*** *(*`src`*)* ***folder must be publically accessible***\n",
871 | "\n",
872 | "##### Folder IDs are found at the end of the URL:\n",
873 | ""
874 | ]
875 | },
876 | {
877 | "cell_type": "markdown",
878 | "metadata": {
879 | "id": "DYreGU9NvCdk",
880 | "colab_type": "text"
881 | },
882 | "source": [
883 | "## ***Extra***"
884 | ]
885 | },
886 | {
887 | "cell_type": "markdown",
888 | "metadata": {
889 | "id": "t0eVljW0O0CG",
890 | "colab_type": "text"
891 | },
892 | "source": [
893 | "### **Bonus 1:** Deleting a Directory *(if needed, just in case)*\n",
894 | "#### ✧ Note: This is ***not required***"
895 | ]
896 | },
897 | {
898 | "cell_type": "code",
899 | "metadata": {
900 | "id": "LgG4fBSgO9Ev",
901 | "colab_type": "code",
902 | "cellView": "form",
903 | "colab": {}
904 | },
905 | "source": [
906 | "#@title ← Run This Cell to Delete a Directory\n",
907 | "import os, shutil\n",
908 | "path = \"\" #@param {type:\"string\"}\n",
909 | "shutil.rmtree(path)\n",
910 | "print(\"Successfully deleted 👍\")"
911 | ],
912 | "execution_count": 0,
913 | "outputs": []
914 | },
915 | {
916 | "cell_type": "markdown",
917 | "metadata": {
918 | "id": "ukxnQC4c0nuR",
919 | "colab_type": "text"
920 | },
921 | "source": [
922 | "# **6.** FFmpeg\n",
923 | "#
"
924 | ]
925 | },
926 | {
927 | "cell_type": "markdown",
928 | "metadata": {
929 | "id": "EFOqhHG6hOVH",
930 | "colab_type": "text"
931 | },
932 | "source": [
933 | "## ***Required to use Scripts:*** Install FFmpeg"
934 | ]
935 | },
936 | {
937 | "cell_type": "code",
938 | "metadata": {
939 | "id": "hFeE-qPuhTiK",
940 | "colab_type": "code",
941 | "colab": {}
942 | },
943 | "source": [
944 | "!apt install ffmpeg"
945 | ],
946 | "execution_count": 0,
947 | "outputs": []
948 | },
949 | {
950 | "cell_type": "markdown",
951 | "metadata": {
952 | "id": "KgNPvGccgwd8",
953 | "colab_type": "text"
954 | },
955 | "source": [
956 | "## FFmpeg Scripts *(Convert, Edit, Trim + more)*"
957 | ]
958 | },
959 | {
960 | "cell_type": "markdown",
961 | "metadata": {
962 | "id": "RDHuIkoi6l9a",
963 | "colab_type": "text"
964 | },
965 | "source": [
966 | "###» Display Media File Codecs + Metadata"
967 | ]
968 | },
969 | {
970 | "cell_type": "markdown",
971 | "metadata": {
972 | "id": "X4yIG_nqYAoH",
973 | "colab_type": "text"
974 | },
975 | "source": [
976 | "> *You can ignore the \"At least one output file must be specified\" error after running this.*\n"
977 | ]
978 | },
979 | {
980 | "cell_type": "code",
981 | "metadata": {
982 | "id": "Sv8au_RO6WUs",
983 | "colab_type": "code",
984 | "cellView": "form",
985 | "colab": {}
986 | },
987 | "source": [
988 | "import os, sys, re\n",
989 | "\n",
990 | "media_file_path = \"\" #@param {type:\"string\"}\n",
991 | "\n",
992 | "os.environ['inputFile'] = media_file_path\n",
993 | "\n",
994 | "!ffmpeg -i \"$inputFile\" -hide_banner"
995 | ],
996 | "execution_count": 0,
997 | "outputs": []
998 | },
999 | {
1000 | "cell_type": "markdown",
1001 | "metadata": {
1002 | "id": "NQ0TxfKeghR8",
1003 | "colab_type": "text"
1004 | },
1005 | "source": [
1006 | "###» Convert *.mkv* ➔ *.mp4* (Lossless)"
1007 | ]
1008 | },
1009 | {
1010 | "cell_type": "code",
1011 | "metadata": {
1012 | "id": "Ls4O5VLwief-",
1013 | "colab_type": "code",
1014 | "cellView": "form",
1015 | "colab": {}
1016 | },
1017 | "source": [
1018 | "import os, sys, re\n",
1019 | "\n",
1020 | "video_file_path = \"\" #@param {type:\"string\"}\n",
1021 | "\n",
1022 | "output_file_path = re.search(\"^[\\/].+\\/\", video_file_path)\n",
1023 | "output_file_path_raw = output_file_path.group(0)\n",
1024 | "delsplit = re.search(\"\\/(?:.(?!\\/))+$\", video_file_path)\n",
1025 | "filename = re.sub(\"^[\\/]\", \"\", delsplit.group(0))\n",
1026 | "filename_raw = re.sub(\".{4}$\", \"\", filename)\n",
1027 | "\n",
1028 | "os.environ['inputFile'] = video_file_path\n",
1029 | "os.environ['outputFile'] = filename_raw\n",
1030 | "os.environ['outputPath'] = output_file_path_raw\n",
1031 | "\n",
1032 | "!ffmpeg -hide_banner -i \"$inputFile\" -c copy -strict experimental \"$outputPath\"\"$outputFile\".mp4"
1033 | ],
1034 | "execution_count": 0,
1035 | "outputs": []
1036 | },
1037 | {
1038 | "cell_type": "markdown",
1039 | "metadata": {
1040 | "id": "FpJXJiRl6-gK",
1041 | "colab_type": "text"
1042 | },
1043 | "source": [
1044 | "###» Trim Video File (Lossless)"
1045 | ]
1046 | },
1047 | {
1048 | "cell_type": "code",
1049 | "metadata": {
1050 | "id": "iFBUeQhn7QTc",
1051 | "colab_type": "code",
1052 | "cellView": "form",
1053 | "colab": {}
1054 | },
1055 | "source": [
1056 | "import os, sys, re\n",
1057 | "\n",
1058 | "video_file_path = \"\" #@param {type:\"string\"}\n",
1059 | "start_time = \"00:00:00.000\" #@param {type:\"string\"}\n",
1060 | "end_time = \"00:01:00.000\" #@param {type:\"string\"}\n",
1061 | "\n",
1062 | "output_file_path = re.search(\"^[\\/].+\\/\", video_file_path)\n",
1063 | "output_file_path_raw = output_file_path.group(0)\n",
1064 | "delsplit = re.search(\"\\/(?:.(?!\\/))+$\", video_file_path)\n",
1065 | "filename = re.sub(\"^[\\/]\", \"\", delsplit.group(0))\n",
1066 | "filename_raw = re.sub(\".{4}$\", \"\", filename)\n",
1067 | "file_extension = re.search(\".{3}$\", filename)\n",
1068 | "file_extension_raw = file_extension.group(0)\n",
1069 | "\n",
1070 | "os.environ['inputFile'] = video_file_path\n",
1071 | "os.environ['outputPath'] = output_file_path_raw\n",
1072 | "os.environ['startTime'] = start_time\n",
1073 | "os.environ['endTime'] = end_time\n",
1074 | "os.environ['fileName'] = filename_raw\n",
1075 | "os.environ['fileExtension'] = file_extension_raw\n",
1076 | "\n",
1077 | "!ffmpeg -hide_banner -i \"$inputFile\" -ss \"$startTime\" -to \"$endTime\" -c copy \"$outputPath\"/\"$fileName\"-TRIM.\"$fileExtension\""
1078 | ],
1079 | "execution_count": 0,
1080 | "outputs": []
1081 | },
1082 | {
1083 | "cell_type": "markdown",
1084 | "metadata": {
1085 | "colab_type": "text",
1086 | "id": "2f-THZmDoOaY"
1087 | },
1088 | "source": [
1089 | "###» Extract Audio from Video File (Lossless)"
1090 | ]
1091 | },
1092 | {
1093 | "cell_type": "code",
1094 | "metadata": {
1095 | "id": "nSeO98YQoTJe",
1096 | "colab_type": "code",
1097 | "cellView": "form",
1098 | "colab": {}
1099 | },
1100 | "source": [
1101 | "import os, sys, re\n",
1102 | "\n",
1103 | "video_file_path = \"\" #@param {type:\"string\"}\n",
1104 | "output_file_extension = 'm4a' #@param [\"m4a\", \"mp3\", \"opus\", \"flac\", \"wav\"]\n",
1105 | "\n",
1106 | "delsplit = re.search(\"\\/(?:.(?!\\/))+$\", video_file_path)\n",
1107 | "output_file_path = re.search(\"^[\\/].+\\/\", video_file_path)\n",
1108 | "filename = re.sub(\"^[\\/]\", \"\", delsplit.group(0))\n",
1109 | "filename_raw = re.sub(\".{4}$\", \"\", filename)\n",
1110 | "\n",
1111 | "os.environ['inputFile'] = video_file_path\n",
1112 | "os.environ['outputPath'] = output_file_path.group(0)\n",
1113 | "os.environ['fileName'] = filename_raw\n",
1114 | "os.environ['fileType'] = output_file_extension\n",
1115 | "\n",
1116 | "!ffmpeg -hide_banner -i \"$inputFile\" -vn -c:a copy \"$outputPath\"/\"$fileName\"-audio.\"$fileType\""
1117 | ],
1118 | "execution_count": 0,
1119 | "outputs": []
1120 | },
1121 | {
1122 | "cell_type": "markdown",
1123 | "metadata": {
1124 | "id": "MSUasbRUDP3B",
1125 | "colab_type": "text"
1126 | },
1127 | "source": [
1128 | "###» Re-encode a Video to a Different Resolution"
1129 | ]
1130 | },
1131 | {
1132 | "cell_type": "code",
1133 | "metadata": {
1134 | "id": "nd2LvSRZCxRe",
1135 | "colab_type": "code",
1136 | "cellView": "form",
1137 | "colab": {}
1138 | },
1139 | "source": [
1140 | "import os, sys, re\n",
1141 | "\n",
1142 | "video_file_path = '' #@param {type:\"string\"}\n",
1143 | "resolution = '1080p' #@param [\"1080p\", \"720p\", \"480p\", \"360p\", \"240p\"]\n",
1144 | "file_type = 'mp4' #@param [\"mkv\", \"mp4\"]\n",
1145 | "\n",
1146 | "delsplit = re.search(\"\\/(?:.(?!\\/))+$\", video_file_path)\n",
1147 | "testsplit = video_file_path.split(\"/\")\n",
1148 | "filename = re.sub(\"^[\\/]\", \"\", delsplit.group(0))\n",
1149 | "filename_raw = re.sub(\".{4}$\", \"\", filename)\n",
1150 | "resolution_raw = re.search(\"[^p]{3,4}\", resolution)\n",
1151 | "output_file_path = re.search(\"^[\\/].+\\/\", video_file_path)\n",
1152 | "\n",
1153 | "os.environ['inputFile'] = video_file_path\n",
1154 | "os.environ['outputPath'] = output_file_path.group(0)\n",
1155 | "os.environ['fileName'] = filename_raw\n",
1156 | "os.environ['fileType'] = file_type\n",
1157 | "os.environ['resolutionHeight'] = resolution_raw.group(0)\n",
1158 | "\n",
1159 | "!ffmpeg -hide_banner -i \"$inputFile\" -vf \"scale=-1:\"$resolutionHeight\"\" -c:a copy -strict experimental \"$outputPath\"/\"$fileName\"-\"$resolutionHeight\"p.\"$fileType\""
1160 | ],
1161 | "execution_count": 0,
1162 | "outputs": []
1163 | },
1164 | {
1165 | "cell_type": "markdown",
1166 | "metadata": {
1167 | "id": "0xI8WiUPji3k",
1168 | "colab_type": "text"
1169 | },
1170 | "source": [
1171 | "# **7.** SSH Access\n",
1172 | "#
\n"
1173 | ]
1174 | },
1175 | {
1176 | "cell_type": "code",
1177 | "metadata": {
1178 | "id": "fsceu1YCkoes",
1179 | "colab_type": "code",
1180 | "cellView": "form",
1181 | "colab": {}
1182 | },
1183 | "source": [
1184 | "#@markdown ← Run to enable SSH acccess\n",
1185 | "#@markdown \n",
1186 | "#Generate root password\n",
1187 | "import random, string\n",
1188 | "password = ''.join(random.choice(string.ascii_letters + string.digits) for i in range(20))\n",
1189 | "#Download ngrok\n",
1190 | "! wget -q -c -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n",
1191 | "! unzip -qq -n ngrok-stable-linux-amd64.zip\n",
1192 | "#Setup sshd\n",
1193 | "! apt-get install -qq -o=Dpkg::Use-Pty=0 openssh-server pwgen > /dev/null\n",
1194 | "#Set root password\n",
1195 | "! echo root:$password | chpasswd\n",
1196 | "! mkdir -p /var/run/sshd\n",
1197 | "! echo \"PermitRootLogin yes\" >> /etc/ssh/sshd_config\n",
1198 | "! echo \"PasswordAuthentication yes\" >> /etc/ssh/sshd_config\n",
1199 | "! echo \"LD_LIBRARY_PATH=/usr/lib64-nvidia\" >> /root/.bashrc\n",
1200 | "! echo \"export LD_LIBRARY_PATH\" >> /root/.bashrc\n",
1201 | "#Run sshd\n",
1202 | "get_ipython().system_raw('/usr/sbin/sshd -D &')\n",
1203 | "#Ask token\n",
1204 | "print(\"Copy authtoken from https://dashboard.ngrok.com/auth\")\n",
1205 | "import getpass\n",
1206 | "authtoken = getpass.getpass()\n",
1207 | "#Create tunnel\n",
1208 | "get_ipython().system_raw('./ngrok authtoken $authtoken && ./ngrok tcp 22 &')\n",
1209 | "#Print root password\n",
1210 | "print(\"Root password: {}\".format(password))\n",
1211 | "#Get public address\n",
1212 | "! curl -s http://localhost:4040/api/tunnels | python3 -c \\\n",
1213 | "\"import sys, json; print(json.load(sys.stdin)['tunnels'][0]['public_url'])\""
1214 | ],
1215 | "execution_count": 0,
1216 | "outputs": []
1217 | },
1218 | {
1219 | "cell_type": "markdown",
1220 | "metadata": {
1221 | "id": "Nl4RbJbX0-a4",
1222 | "colab_type": "text"
1223 | },
1224 | "source": [
1225 | "# **8.** youtube-dl\n",
1226 | "#
"
1227 | ]
1228 | },
1229 | {
1230 | "cell_type": "code",
1231 | "metadata": {
1232 | "id": "dCK-puiMnHYj",
1233 | "colab_type": "code",
1234 | "cellView": "form",
1235 | "colab": {}
1236 | },
1237 | "source": [
1238 | "#@markdown ← Click Here to use youtube-dl
\n",
1239 | "\n",
1240 | "import os, uuid, urllib.parse\n",
1241 | "import ipywidgets as widgets\n",
1242 | "Archive = False\n",
1243 | "\n",
1244 | "from glob import glob\n",
1245 | "from urllib.parse import urlparse, parse_qs\n",
1246 | "from IPython.display import HTML, clear_output, YouTubeVideo\n",
1247 | "from IPython.utils.io import ask_yes_no\n",
1248 | "from google.colab import output, files\n",
1249 | "\n",
1250 | "Links = widgets.Textarea(placeholder='''Video/Playlist Link\n",
1251 | "(one link per line)''')\n",
1252 | "\n",
1253 | "VideoQ = widgets.Dropdown(options=[\"Best Quality (VP9 upto 4K)\", \"Best Compatibility (H.264 upto 1080p)\"])\n",
1254 | "\n",
1255 | "AudioQ = widgets.Dropdown(options=[\"Best Quality (Opus)\", \"Best Compatibility (M4A)\"])\n",
1256 | "\n",
1257 | "Subtitle = widgets.ToggleButton(value=True, description=\"Subtitle\", button_style=\"info\", tooltip=\"Subtitle\")\n",
1258 | "\n",
1259 | "SavePathYT = widgets.Dropdown(options=[\"/content\", \"/content/Downloads\"])\n",
1260 | "\n",
1261 | "AudioOnly = widgets.ToggleButton(value=False, description=\"Audio Only\", button_style=\"\", tooltip=\"Audio Only\")\n",
1262 | "\n",
1263 | "Resolution = widgets.Select(options=[\"Highest\", \"4K\", \"1440p\", \"1080p\", \"720p\", \"480p\", \"360p\", \"240p\", \"144p\"], value=\"Highest\")\n",
1264 | "\n",
1265 | "Extension = widgets.Select(options=[\"mkv\", \"webm\"], value=\"mkv\")\n",
1266 | "\n",
1267 | "UsernameYT = widgets.Text(placeholder=\"Username\")\n",
1268 | "\n",
1269 | "PasswordYT = widgets.Text(placeholder=\"Password\")\n",
1270 | "\n",
1271 | "SecAuth = widgets.Text(placeholder=\"2nd Factor Authentication\")\n",
1272 | "\n",
1273 | "VideoPW = widgets.Text(placeholder=\"Video Password\")\n",
1274 | "\n",
1275 | "GEOBypass = widgets.Dropdown(options=[\"Disable\", \"Hide\", \"AD\", \"AE\", \"AF\", \"AG\", \"AI\", \"AL\", \"AM\", \"AO\", \"AQ\", \"AR\", \"AS\", \"AT\", \"AU\", \"AW\", \"AX\", \"AZ\", \"BA\", \"BB\", \"BD\", \"BE\", \"BF\", \"BG\", \"BH\", \"BI\", \"BJ\", \"BL\", \"BM\", \"BN\", \"BO\", \"BQ\", \"BR\", \"BS\", \"BT\", \"BV\", \"BW\", \"BY\", \"BZ\", \"CA\", \"CC\", \"CD\", \"CF\", \"CG\", \"CH\", \"CI\", \"CK\", \"CL\", \"CM\", \"CN\", \"CO\", \"CR\", \"CU\", \"CV\", \"CW\", \"CX\", \"CY\", \"CZ\", \"DE\", \"DJ\", \"DK\", \"DM\", \"DO\", \"DZ\", \"EC\", \"EE\", \"EG\", \"EH\", \"ER\", \"ES\", \"ET\", \"FI\", \"FJ\", \"FK\", \"FM\", \"FO\", \"FR\", \"GA\", \"GB\", \"GD\", \"GE\", \"GF\", \"GG\", \"GH\", \"GI\", \"GL\", \"GM\", \"GN\", \"GP\", \"GQ\", \"GR\", \"GS\", \"GT\", \"GU\", \"GW\", \"GY\", \"HK\", \"HM\", \"HN\", \"HR\", \"HT\", \"HU\", \"ID\", \"IE\", \"IL\", \"IM\", \"IN\", \"IO\", \"IQ\", \"IR\", \"IS\", \"IT\", \"JE\", \"JM\", \"JO\", \"JP\", \"KE\", \"KG\", \"KH\", \"KI\", \"KM\", \"KN\", \"KP\", \"KR\", \"KW\", \"KY\", \"KZ\", \"LA\", \"LB\", \"LC\", \"LI\", \"LK\", \"LR\", \"LS\", \"LT\", \"LU\", \"LV\", \"LY\", \"MA\", \"MC\", \"MD\", \"ME\", \"MF\", \"MG\", \"MH\", \"MK\", \"ML\", \"MM\", \"MN\", \"MO\", \"MP\", \"MQ\", \"MR\", \"MS\", \"MT\", \"MU\", \"MV\", \"MW\", \"MX\", \"MY\", \"MZ\", \"NA\", \"NC\", \"NE\", \"NF\", \"NG\", \"NI\", \"NL\", \"NO\", \"NP\", \"NR\", \"NU\", \"NZ\", \"OM\", \"PA\", \"PE\", \"PF\", \"PG\", \"PH\", \"PK\", \"PL\", \"PM\", \"PN\", \"PR\", \"PS\", \"PT\", \"PW\", \"PY\", \"QA\", \"RE\", \"RO\", \"RS\", \"RU\", \"RW\", \"SA\", \"SB\", \"SC\", \"SD\", \"SE\", \"SG\", \"SH\", \"SI\", \"SJ\", \"SK\", \"SL\", \"SM\", \"SN\", \"SO\", \"SR\", \"SS\", \"ST\", \"SV\", \"SX\", \"SY\", \"SZ\", \"TC\", \"TD\", \"TF\", \"TG\", \"TH\", \"TJ\", \"TK\", \"TL\", \"TM\", \"TN\", \"TO\", \"TR\", \"TT\", \"TV\", \"TW\", \"TZ\", \"UA\", \"UG\", \"UM\", \"US\", \"UY\", \"UZ\", \"VA\", \"VC\", \"VE\", \"VG\", \"VI\", \"VN\", \"VU\", \"WF\", \"WS\", \"YE\", \"YT\", \"ZA\", \"ZM\", \"ZW\"])\n",
1276 | "\n",
1277 | "ProxyYT = widgets.Text(placeholder=\"Proxy URL\")\n",
1278 | "\n",
1279 | "MinSleep = widgets.BoundedIntText(value=0, min=0, max=300, step=1, description=\"Min:\")\n",
1280 | "\n",
1281 | "MaxSleep = widgets.BoundedIntText(value=0, min=0, max=300, step=1, description=\"Max:\")\n",
1282 | "\n",
1283 | "ExtraArg = widgets.Text(placeholder=\"Extra Arguments\")\n",
1284 | "\n",
1285 | "class MakeButton(object):\n",
1286 | " def __init__(self, title, callback, style):\n",
1287 | " self._title = title\n",
1288 | " self._callback = callback\n",
1289 | " self._style = style\n",
1290 | " def _repr_html_(self):\n",
1291 | " callback_id = 'button-' + str(uuid.uuid4())\n",
1292 | " output.register_callback(callback_id, self._callback)\n",
1293 | " if self._style != \"\":\n",
1294 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button mod-\" + self._style\n",
1295 | " else:\n",
1296 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button\"\n",
1297 | " template = \"\"\"\n",
1298 | " \"\"\"\n",
1304 | " html = template.format(title=self._title, callback_id=callback_id, style_html=style_html)\n",
1305 | " return html\n",
1306 | " \n",
1307 | "def MakeLabel(description, button_style):\n",
1308 | " return widgets.Button(description=description, disabled=True, button_style=button_style)\n",
1309 | "\n",
1310 | "def upload_archive():\n",
1311 | " if ask_yes_no(\"Do you already have an archive file? (y/n)\", default=\"\", interrupt=\"\"):\n",
1312 | " try:\n",
1313 | " display(HTML(\"Please upload an archive from your computer.
\"))\n",
1314 | " UploadConfig = files.upload().keys()\n",
1315 | " clear_output(wait=True)\n",
1316 | " if len(UploadConfig) == 0:\n",
1317 | " return display(HTML(\"File upload has been cancelled during upload file.
\"))\n",
1318 | " elif len(UploadConfig) == 1:\n",
1319 | " for fn in UploadConfig:\n",
1320 | " if os.path.isfile(\"/content/\" + fn):\n",
1321 | " get_ipython().system_raw(\"mv -f \" + \"\\\"\" + fn + \"\\\" /root/.youtube-dl.txt && chmod 666 /root/.youtube-dl.txt\")\n",
1322 | " AudioOnly.observe(AudioOnlyChange)\n",
1323 | " Subtitle.observe(SubtitleChange)\n",
1324 | " AudioQ.observe(AudioQChange)\n",
1325 | " ShowYT()\n",
1326 | " else:\n",
1327 | " return display(HTML(\"File upload has been failed during upload file.
\"))\n",
1328 | " else:\n",
1329 | " for fn in UploadConfig:\n",
1330 | " get_ipython().system_raw(\"rm -f \" + \"\\\"\" + fn + \"\\\"\")\n",
1331 | " return display(HTML(\"Please uploading only one file at a time.
\"))\n",
1332 | " except:\n",
1333 | " clear_output(wait=True)\n",
1334 | " return display(HTML(\"Error occurred during upload file.
\"))\n",
1335 | " else:\n",
1336 | " get_ipython().system_raw(\"touch '/root/.youtube-dl.txt'\")\n",
1337 | " AudioOnly.observe(AudioOnlyChange)\n",
1338 | " Subtitle.observe(SubtitleChange)\n",
1339 | " AudioQ.observe(AudioQChange)\n",
1340 | " ShowYT()\n",
1341 | "\n",
1342 | "def RefreshPathYT():\n",
1343 | " if os.path.exists(\"/content/drive/\"):\n",
1344 | " if os.path.exists(\"/content/drive/Shared drives/\"):\n",
1345 | " SavePathYT.options = [\"/content\", \"/content/Downloads\", \"/content/drive/My Drive\"] + glob(\"/content/drive/My Drive/*/\") + glob(\"/content/drive/Shared drives/*/\")\n",
1346 | " else:\n",
1347 | " SavePathYT.options = [\"/content\", \"/content/Downloads\", \"/content/drive/My Drive\"] + glob(\"/content/drive/My Drive/*/\")\n",
1348 | " else:\n",
1349 | " SavePathYT.options = [\"/content\", \"/content/Downloads\"]\n",
1350 | "\n",
1351 | "def AudioOnlyChange(change):\n",
1352 | " if change[\"type\"] == \"change\" and change[\"new\"]:\n",
1353 | " VideoQ.disabled = True\n",
1354 | " Subtitle.disabled = True\n",
1355 | " if Subtitle.value:\n",
1356 | " Subtitle.button_style = \"info\"\n",
1357 | " else:\n",
1358 | " Subtitle.button_style = \"\"\n",
1359 | " Resolution.disabled = True\n",
1360 | " Extension.options = [\"best\", \"aac\", \"flac\", \"mp3\", \"m4a\", \"opus\", \"vorbis\", \"wav\"]\n",
1361 | " Extension.value = \"best\"\n",
1362 | " AudioOnly.button_style = \"info\"\n",
1363 | " elif change[\"type\"] == \"change\" and change[\"new\"] == False:\n",
1364 | " VideoQ.disabled = False\n",
1365 | " Subtitle.disabled = False\n",
1366 | " if Subtitle.value:\n",
1367 | " Subtitle.button_style = \"info\"\n",
1368 | " else:\n",
1369 | " Subtitle.button_style = \"\"\n",
1370 | " Resolution.disabled = False\n",
1371 | " if AudioQ.value == \"Best Quality (Opus)\":\n",
1372 | " Extension.options = [\"mkv\", \"webm\"]\n",
1373 | " else:\n",
1374 | " Extension.options = [\"mkv\", \"mp4\", \"webm\"]\n",
1375 | " Extension.value = \"mkv\"\n",
1376 | " AudioOnly.button_style = \"\"\n",
1377 | "\n",
1378 | "def SubtitleChange(change):\n",
1379 | " if change[\"type\"] == \"change\" and change[\"new\"]:\n",
1380 | " Subtitle.button_style = \"info\"\n",
1381 | " elif change[\"type\"] == \"change\" and change[\"new\"] == False:\n",
1382 | " Subtitle.button_style = \"\"\n",
1383 | "\n",
1384 | "def AudioQChange(change):\n",
1385 | " if change[\"type\"] == \"change\" and change[\"new\"] == \"Best Quality (Opus)\":\n",
1386 | " Extension.options = [\"mkv\", \"webm\"]\n",
1387 | " Extension.value = \"mkv\"\n",
1388 | " elif change[\"type\"] == \"change\" and change[\"new\"] == \"Best Compatibility (M4A)\":\n",
1389 | " Extension.options = [\"mkv\", \"mp4\", \"webm\"]\n",
1390 | " Extension.value = \"mkv\"\n",
1391 | "\n",
1392 | "def ShowYT():\n",
1393 | " clear_output(wait=True)\n",
1394 | " RefreshPathYT()\n",
1395 | " display(widgets.HBox([widgets.VBox([widgets.HTML(\"Link:\"), Links,\n",
1396 | " widgets.HTML(\"For website that require an account:\"), UsernameYT, PasswordYT, SecAuth, VideoPW,\n",
1397 | " widgets.HTML(\"GEO Bypass Country:\"), GEOBypass,\n",
1398 | " widgets.HTML(\"Proxy:\"), ProxyYT,\n",
1399 | " widgets.HTML(\"Sleep Interval (second):\"), MinSleep, MaxSleep]),\n",
1400 | " widgets.VBox([widgets.HTML(\"Video Quality:\"), VideoQ, widgets.HTML(\"Resolution:\"), Resolution,\n",
1401 | " widgets.HTML(\"Audio Quality:\"), AudioQ, widgets.HTML(\"Extension:\"), Extension,\n",
1402 | " widgets.HTML(\"Extra Options:\"), widgets.HBox([Subtitle, AudioOnly]),\n",
1403 | " widgets.HTML(\"Extra Arguments:\"), ExtraArg])]), HTML(\"Save Location:
\"),\n",
1404 | " SavePathYT, MakeButton(\"Refresh\", RefreshPathYT, \"\"))\n",
1405 | " if not os.path.exists(\"/content/drive/\"):\n",
1406 | " display(HTML(\"*If you want to save in Google Drive please run the cell below.\"))\n",
1407 | " display(HTML(\"
\"), MakeButton(\"Download\", DownloadYT, \"info\"))\n",
1408 | "\n",
1409 | "def DownloadYT():\n",
1410 | " if Links.value.strip():\n",
1411 | " Count = 0\n",
1412 | " Total = str(len(Links.value.splitlines()))\n",
1413 | " # Account Check\n",
1414 | " if UsernameYT.value.strip() and PasswordYT.value.strip():\n",
1415 | " accountC = \"--username \\\"\" + UsernameYT.value + \"\\\" --password \\\"\" + PasswordYT.value + \"\\\"\"\n",
1416 | " else:\n",
1417 | " accountC = \"\"\n",
1418 | " if SecAuth.value.strip():\n",
1419 | " secauthC = \"-2 \" + SecAuth.value\n",
1420 | " else:\n",
1421 | " secauthC = \"\"\n",
1422 | " if VideoPW.value.strip():\n",
1423 | " videopwC = \"--video-password \" + VideoPW.value\n",
1424 | " else:\n",
1425 | " videopwC = \"\"\n",
1426 | " # Proxy\n",
1427 | " if ProxyYT.value.strip():\n",
1428 | " proxyytC = \"--proxy \" + ProxyYT.value\n",
1429 | " else:\n",
1430 | " proxyytC = \"\"\n",
1431 | " # GEO Bypass\n",
1432 | " if GEOBypass.value == \"Disable\":\n",
1433 | " geobypass = \"\"\n",
1434 | " elif GEOBypass.value == \"Hide\":\n",
1435 | " geobypass = \"--geo-bypass\"\n",
1436 | " else:\n",
1437 | " geobypass = \"--geo-bypass-country \" + GEOBypass.value\n",
1438 | " # Video Quality\n",
1439 | " if VideoQ.value == \"Best Quality (VP9 upto 4K)\":\n",
1440 | " videoqC = \"webm\"\n",
1441 | " else:\n",
1442 | " videoqC = \"mp4\"\n",
1443 | " # Audio Quality\n",
1444 | " if AudioQ.value == \"Best Quality (Opus)\":\n",
1445 | " audioqC = \"webm\"\n",
1446 | " else:\n",
1447 | " audioqC = \"m4a\"\n",
1448 | " # Audio Only Check\n",
1449 | " if AudioOnly.value:\n",
1450 | " subtitleC = \"\"\n",
1451 | " thumbnailC = \"\"\n",
1452 | " extC = \"-x --audio-quality 0 --audio-format \" + Extension.value\n",
1453 | " codecC = \"bestaudio[ext=\" + audioqC + \"]/bestaudio/best\"\n",
1454 | " else:\n",
1455 | " if Subtitle.value:\n",
1456 | " subtitleC = \"--all-subs --convert-subs srt --embed-subs\"\n",
1457 | " else:\n",
1458 | " subtitleC = \"\"\n",
1459 | " if Extension.value == \"mp4\":\n",
1460 | " thumbnailC = \"--embed-thumbnail\"\n",
1461 | " else:\n",
1462 | " thumbnailC = \"\"\n",
1463 | " extC = \"--merge-output-format \" + Extension.value\n",
1464 | " if Resolution.value == \"Highest\":\n",
1465 | " codecC = \"bestvideo[ext=\" + videoqC + \"]+bestaudio[ext=\" + audioqC + \"]/bestvideo+bestaudio/best\"\n",
1466 | " else:\n",
1467 | " codecC = \"bestvideo[ext=\" + videoqC + \",height<=\" + Resolution.value.replace(\"4K\", \"2160\").replace(\"p\", \"\") + \"]+bestaudio[ext=\" + audioqC + \"]/bestvideo[height<=\" + Resolution.value.replace(\"4K\", \"2160\").replace(\"p\", \"\") + \"]+bestaudio/bestvideo+bestaudio/best\"\n",
1468 | " # Archive\n",
1469 | " if os.path.isfile(\"/root/.youtube-dl.txt\"):\n",
1470 | " archiveC = \"--download-archive \\\"/root/.youtube-dl.txt\\\"\"\n",
1471 | " else:\n",
1472 | " archiveC = \"\"\n",
1473 | " # Sleep Interval\n",
1474 | " if MinSleep.value > 0 and MaxSleep.value > 0:\n",
1475 | " minsleepC = \"--min-sleep-interval \" + MinSleep.value\n",
1476 | " maxsleepC = \"--max-sleep-interval \" + MaxSleep.value\n",
1477 | " else:\n",
1478 | " minsleepC = \"\"\n",
1479 | " maxsleepC = \"\"\n",
1480 | " # Extra Arguments\n",
1481 | " extraargC = ExtraArg.value\n",
1482 | " for Link in Links.value.splitlines():\n",
1483 | " clear_output(wait=True)\n",
1484 | " Count += 1\n",
1485 | " display(HTML(\"Processing link \" + str(Count) + \" out of \" + Total + \"
\"))\n",
1486 | " if \"youtube.com\" in Link or \"youtu.be\" in Link:\n",
1487 | " display(HTML(\"Currently downloading...
\"), YouTubeVideo(Link, width=640, height=360), HTML(\"
\"))\n",
1488 | " else:\n",
1489 | " display(HTML(\"
\"))\n",
1490 | " if (\"youtube.com\" in Link or \"youtu.be\" in Link) and \"list=\" in Link:\n",
1491 | " !youtube-dl -i --no-warnings --yes-playlist --add-metadata $accountC $secauthC $videopwC $minsleepC $maxsleepC $geobypass $proxyytC $extC $thumbnailC $subtitleC $archiveC $extraargC -f \"$codecC\" -o \"/root/.YouTube-DL/%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s\" \"$Link\"\n",
1492 | " else:\n",
1493 | " !youtube-dl -i --no-warnings --yes-playlist --add-metadata $accountC $secauthC $videopwC $minsleepC $maxsleepC $geobypass $proxyytC $extC $thumbnailC $subtitleC $archiveC $extraargC -f \"$codecC\" -o \"/root/.YouTube-DL/%(title)s.%(ext)s\" \"$Link\"\n",
1494 | " if not os.path.exists(SavePathYT.value):\n",
1495 | " get_ipython().system_raw(\"mkdir -p -m 666 \" + SavePathYT.value)\n",
1496 | " get_ipython().system_raw(\"mv /root/.YouTube-DL/* '\" + SavePathYT.value + \"/'\")\n",
1497 | " # Archive Download\n",
1498 | " if os.path.isfile(\"/root/.youtube-dl.txt\"):\n",
1499 | " files.download(\"/root/.youtube-dl.txt\")\n",
1500 | " ShowYT()\n",
1501 | "\n",
1502 | "if not os.path.isfile(\"/usr/local/bin/youtube-dl\"):\n",
1503 | " get_ipython().system_raw(\"rm -rf /content/sample_data/ && mkdir -p -m 666 /root/.YouTube-DL/ && apt-get install atomicparsley && curl -L https://yt-dl.org/downloads/latest/youtube-dl -o /usr/local/bin/youtube-dl && chmod a+rx /usr/local/bin/youtube-dl\")\n",
1504 | "if Archive:\n",
1505 | " upload_archive()\n",
1506 | "else:\n",
1507 | " AudioOnly.observe(AudioOnlyChange)\n",
1508 | " Subtitle.observe(SubtitleChange)\n",
1509 | " AudioQ.observe(AudioQChange)\n",
1510 | " ShowYT()"
1511 | ],
1512 | "execution_count": 0,
1513 | "outputs": []
1514 | },
1515 | {
1516 | "cell_type": "markdown",
1517 | "metadata": {
1518 | "id": "QlsUJhNwyeV3",
1519 | "colab_type": "text"
1520 | },
1521 | "source": [
1522 | "# **9**. rcloneLab\n",
1523 | "#
"
1524 | ]
1525 | },
1526 | {
1527 | "cell_type": "code",
1528 | "metadata": {
1529 | "id": "9qOSyk-RCTCz",
1530 | "colab_type": "code",
1531 | "cellView": "form",
1532 | "colab": {}
1533 | },
1534 | "source": [
1535 | "# ============================= FORM ============================= #\n",
1536 | "# @markdown ####← Execute rClone\n",
1537 | "# @markdown ---\n",
1538 | "# @markdown ##### Quick move (Select and leave all boxes):\n",
1539 | "# @markdown #####{\n",
1540 | "Quick_Move = \"None\" # @param [\"None\",\"simpleTorrent\", \"Peerflix\", \"qBittorrent\", \"extract\", \"error\"]\n",
1541 | "# @markdown #####}\n",
1542 | "\n",
1543 | "Mode = \"Move\" # @param [\"Move\", \"Copy\", \"Sync\", \"Verify\", \"Dedupe\", \"Clean Empty Dirs\", \"Empty Trash\"]\n",
1544 | "Source = \"\" # @param {type:\"string\"}\n",
1545 | "Destination = \"\" # @param {type:\"string\"}\n",
1546 | "Extra_Arguments = \"\" # @param {type:\"string\"}\n",
1547 | "COPY_SHARED_FILES = False # @param{type: \"boolean\"}\n",
1548 | "Compare = \"Size & Checksum\"\n",
1549 | "TRANSFERS, CHECKERS = 20, 20\n",
1550 | "THROTTLE_TPS = True\n",
1551 | "BRIDGE_TRANSFER = False # @param{type: \"boolean\"}\n",
1552 | "FAST_LIST = False # @param{type: \"boolean\"}\n",
1553 | "OPTIMIZE_GDRIVE = True\n",
1554 | "SIMPLE_LOG = True\n",
1555 | "RECORD_LOGFILE = False # @param{type: \"boolean\"}\n",
1556 | "SKIP_NEWER_FILE = False\n",
1557 | "SKIP_EXISTED = False\n",
1558 | "SKIP_UPDATE_MODTIME = False\n",
1559 | "ONE_FILE_SYSTEM = False\n",
1560 | "LOG_LEVEL = \"DEBUG\"\n",
1561 | "SYNC_MODE = \"Delete after transfering\"\n",
1562 | "SYNC_TRACK_RENAME = True\n",
1563 | "DEDUPE_MODE = \"Largest\"\n",
1564 | "USE_TRASH = True\n",
1565 | "DRY_RUN = False # @param{type: \"boolean\"}\n",
1566 | "# ================================================================ #\n",
1567 | "if Quick_Move == \"None\":\n",
1568 | " pass\n",
1569 | "elif Quick_Move == \"simpleTorrent\" and Source == \"\" and Destination == \"\":\n",
1570 | " Mode = \"Move\"\n",
1571 | " Source = \"/content/downloads\"\n",
1572 | " Destination = \"/content/drive/My Drive\" \n",
1573 | "elif Quick_Move == \"Peerflix\" and Source == \"\" and Destination == \"\":\n",
1574 | " Mode = \"Move\"\n",
1575 | " Source = \"/content/peerflix\"\n",
1576 | " Destination = \"/content/drive/My Drive\" \n",
1577 | "elif Quick_Move == \"qBittorrent\" and Source == \"\" and Destination == \"\":\n",
1578 | " Mode = \"Move\"\n",
1579 | " Source = \"/content/qBittorrent\"\n",
1580 | " Destination = \"/content/drive/My Drive\"\n",
1581 | "elif Quick_Move == \"extract\" and Source == \"\" and Destination == \"\":\n",
1582 | " Mode = \"Move\"\n",
1583 | " Source = \"/content/extract\"\n",
1584 | " Destination = \"/content/drive/My Drive\"\n",
1585 | "elif Quick_Move == \"error\":\n",
1586 | " raise Exception(\"You are selected Error!\")\n",
1587 | "\n",
1588 | "from os import path as _p\n",
1589 | "\n",
1590 | "if not _p.exists(\"/root/.ipython/rlab_utils.py\"):\n",
1591 | " from shlex import split as _spl\n",
1592 | " from subprocess import run\n",
1593 | "\n",
1594 | " shellCmd = \"wget -qq https://biplobsd.github.io/RLabClone/res/rlab_utils.py \\\n",
1595 | " -O /root/.ipython/rlab_utils.py\"\n",
1596 | " run(_spl(shellCmd))\n",
1597 | "\n",
1598 | "from datetime import datetime as _dt\n",
1599 | "from rlab_utils import (\n",
1600 | " displayOutput,\n",
1601 | " checkAvailable,\n",
1602 | " runSh,\n",
1603 | " prepareSession,\n",
1604 | " PATH_RClone_Config,\n",
1605 | " accessSettingFile,\n",
1606 | " memGiB,\n",
1607 | ")\n",
1608 | "\n",
1609 | "\n",
1610 | "def populateActionArg():\n",
1611 | " if Mode == \"Copy\":\n",
1612 | " actionArg = \"copy\"\n",
1613 | " elif Mode == \"Sync\":\n",
1614 | " actionArg = \"sync\"\n",
1615 | " elif Mode == \"Verify\":\n",
1616 | " actionArg = \"check\"\n",
1617 | " elif Mode == \"Dedupe\":\n",
1618 | " actionArg = \"dedupe largest\"\n",
1619 | " elif Mode == \"Clean Empty Dirs\":\n",
1620 | " actionArg = \"rmdirs\"\n",
1621 | " elif Mode == \"Empty Trash\":\n",
1622 | " actionArg = \"delete\"\n",
1623 | " else:\n",
1624 | " actionArg = \"move\"\n",
1625 | "\n",
1626 | " return actionArg\n",
1627 | "\n",
1628 | "\n",
1629 | "def populateCompareArg():\n",
1630 | " if Compare == \"Mod-Time\":\n",
1631 | " compareArg = \"--ignore-size\"\n",
1632 | " elif Compare == \"Size\":\n",
1633 | " compareArg = \"--size-only\"\n",
1634 | " elif Compare == \"Checksum\":\n",
1635 | " compareArg = \"-c --ignore-size\"\n",
1636 | " else:\n",
1637 | " compareArg = \"-c\"\n",
1638 | "\n",
1639 | " return compareArg\n",
1640 | "\n",
1641 | "\n",
1642 | "def populateOptimizeGDriveArg():\n",
1643 | " return (\n",
1644 | " \"--buffer-size 256M \\\n",
1645 | " --drive-chunk-size 256M \\\n",
1646 | " --drive-upload-cutoff 256M \\\n",
1647 | " --drive-acknowledge-abuse \\\n",
1648 | " --drive-keep-revision-forever\"\n",
1649 | " if OPTIMIZE_GDRIVE\n",
1650 | " else \"--buffer-size 128M\"\n",
1651 | " )\n",
1652 | "\n",
1653 | "\n",
1654 | "def populateGDriveCopyArg():\n",
1655 | " if BRIDGE_TRANSFER and memGiB() < 13:\n",
1656 | " global TRANSFERS, CHECKERS\n",
1657 | " TRANSFERS, CHECKERS = 10, 80\n",
1658 | " else:\n",
1659 | " pass\n",
1660 | " return \"--disable copy\" if BRIDGE_TRANSFER else \"--drive-server-side-across-configs\"\n",
1661 | "\n",
1662 | "\n",
1663 | "def populateStatsArg():\n",
1664 | " statsArg = \"--stats-one-line --stats=5s\" if SIMPLE_LOG else \"--stats=5s -P\"\n",
1665 | " if LOG_LEVEL != \"OFF\":\n",
1666 | " statsArg += \" -v\" if SIMPLE_LOG else \"-vv\"\n",
1667 | " elif LOG_LEVEL == \"INFO\":\n",
1668 | " statsArg += \" --log-level INFO\"\n",
1669 | " elif LOG_LEVEL == \"ERROR\":\n",
1670 | " statsArg += \" --log-level ERROR\"\n",
1671 | " else:\n",
1672 | " statsArg += \" --log-level DEBUG\"\n",
1673 | " return statsArg\n",
1674 | "\n",
1675 | "\n",
1676 | "def populateSyncModeArg():\n",
1677 | " if Mode != \"Sync\":\n",
1678 | " return \"\"\n",
1679 | " elif SYNC_MODE == \"Delete before transfering\":\n",
1680 | " syncModeArg = \"--delete-before\"\n",
1681 | " elif SYNC_MODE == \"Delete after transfering\":\n",
1682 | " syncModeArg = \"--delete-after\"\n",
1683 | " else:\n",
1684 | " syncModeArg = \"--delete-during\"\n",
1685 | " if SYNC_TRACK_RENAME:\n",
1686 | " syncModeArg += \" --track-renames\"\n",
1687 | " return syncModeArg\n",
1688 | "\n",
1689 | "\n",
1690 | "def populateDedupeModeArg():\n",
1691 | " if DEDUPE_MODE == \"Interactive\":\n",
1692 | " dedupeModeArg = \"--dedupe-mode interactive\"\n",
1693 | " elif DEDUPE_MODE == \"Skip\":\n",
1694 | " dedupeModeArg = \"--dedupe-mode skip\"\n",
1695 | " elif DEDUPE_MODE == \"First\":\n",
1696 | " dedupeModeArg = \"--dedupe-mode first\"\n",
1697 | " elif DEDUPE_MODE == \"Newest\":\n",
1698 | " dedupeModeArg = \"--dedupe-mode newest\"\n",
1699 | " elif DEDUPE_MODE == \"Oldest\":\n",
1700 | " dedupeModeArg = \"--dedupe-mode oldest\"\n",
1701 | " elif DEDUPE_MODE == \"Rename\":\n",
1702 | " dedupeModeArg = \"--dedupe-mode rename\"\n",
1703 | " else:\n",
1704 | " dedupeModeArg = \"--dedupe-mode largest\"\n",
1705 | "\n",
1706 | " return dedupeModeArg\n",
1707 | "\n",
1708 | "\n",
1709 | "def generateCmd():\n",
1710 | " sharedFilesArgs = (\n",
1711 | " \"--drive-shared-with-me --files-from /content/upload.txt --no-traverse\"\n",
1712 | " if COPY_SHARED_FILES\n",
1713 | " else \"\"\n",
1714 | " )\n",
1715 | "\n",
1716 | " logFileArg = f\"--log-file /content/rclone_log.txt -vv -P\"\n",
1717 | "\n",
1718 | " args = [\n",
1719 | " \"rclone\",\n",
1720 | " f\"--config {PATH_RClone_Config}/rclone.conf\",\n",
1721 | " '--user-agent \"Mozilla\"',\n",
1722 | " populateActionArg(),\n",
1723 | " f'\"{Source}\"',\n",
1724 | " f'\"{Destination}\"' if Mode in (\"Move\", \"Copy\", \"Sync\") else \"\",\n",
1725 | " f\"--transfers {str(TRANSFERS)}\",\n",
1726 | " f\"--checkers {str(CHECKERS)}\",\n",
1727 | " ]\n",
1728 | "\n",
1729 | " if Mode == \"Verify\":\n",
1730 | " args.append(\"--one-way\")\n",
1731 | " elif Mode == \"Empty Trash\":\n",
1732 | " args.append(\"--drive-trashed-only --drive-use-trash=false\")\n",
1733 | " else:\n",
1734 | " args.extend(\n",
1735 | " [\n",
1736 | " populateGDriveCopyArg(),\n",
1737 | " populateSyncModeArg(),\n",
1738 | " populateCompareArg(),\n",
1739 | " populateOptimizeGDriveArg(),\n",
1740 | " \"-u\" if SKIP_NEWER_FILE else \"\",\n",
1741 | " \"--ignore-existing\" if SKIP_EXISTED else \"\",\n",
1742 | " \"--no-update-modtime\" if SKIP_UPDATE_MODTIME else \"\",\n",
1743 | " \"--one-file-system\" if ONE_FILE_SYSTEM else \"\",\n",
1744 | " \"--tpslimit 95 --tpslimit-burst 40\" if THROTTLE_TPS else \"\",\n",
1745 | " \"--fast-list\" if FAST_LIST else \"\",\n",
1746 | " \"--delete-empty-src-dirs\" if Mode == \"Move\" else \"\",\n",
1747 | " ]\n",
1748 | " )\n",
1749 | " args.extend(\n",
1750 | " [\n",
1751 | " \"-n\" if DRY_RUN else \"\",\n",
1752 | " populateStatsArg() if not RECORD_LOGFILE else logFileArg,\n",
1753 | " sharedFilesArgs,\n",
1754 | " Extra_Arguments,\n",
1755 | " ]\n",
1756 | " )\n",
1757 | "\n",
1758 | " return args\n",
1759 | "\n",
1760 | "\n",
1761 | "def executeRclone():\n",
1762 | " prepareSession()\n",
1763 | " if Source.strip() == \"\":\n",
1764 | " displayOutput(\"❌ The Source field is empty.\")\n",
1765 | " return\n",
1766 | " if checkAvailable(\"/content/rclone_log.txt\"):\n",
1767 | " if not checkAvailable(\"/content/logfiles\"):\n",
1768 | " runSh(\"mkdir -p -m 666 /content/logfiles\")\n",
1769 | " job = accessSettingFile(\"job.txt\")\n",
1770 | " runSh(\n",
1771 | " f'mv /content/rclone_log.txt /content/logfiles/{job[\"title\"]}_{job[\"status\"]}_logfile.txt'\n",
1772 | " )\n",
1773 | "\n",
1774 | " onGoingJob = {\n",
1775 | " \"title\": f'{Mode}_{Source}_{Destination}_{_dt.now().strftime(\"%a-%H-%M-%S\")}',\n",
1776 | " \"status\": \"ongoing\",\n",
1777 | " }\n",
1778 | " accessSettingFile(\"job.txt\", onGoingJob)\n",
1779 | "\n",
1780 | " cmd = \" \".join(generateCmd())\n",
1781 | " runSh(cmd, output=True)\n",
1782 | " displayOutput(Mode, \"success\")\n",
1783 | "\n",
1784 | " onGoingJob[\"status\"] = \"finished\"\n",
1785 | " accessSettingFile(\"job.txt\", onGoingJob)\n",
1786 | "\n",
1787 | "executeRclone()\n"
1788 | ],
1789 | "execution_count": 0,
1790 | "outputs": []
1791 | },
1792 | {
1793 | "cell_type": "code",
1794 | "metadata": {
1795 | "id": "whyei9P7GIsM",
1796 | "colab_type": "code",
1797 | "cellView": "form",
1798 | "colab": {}
1799 | },
1800 | "source": [
1801 | "#@markdown rclone webui
\n",
1802 | "import os, signal\n",
1803 | "import random\n",
1804 | "import string\n",
1805 | "import urllib.request\n",
1806 | "from IPython.display import HTML, clear_output\n",
1807 | "import time\n",
1808 | "\n",
1809 | "#####################################\n",
1810 | "USE_FREE_TOKEN = True # @param {type:\"boolean\"}\n",
1811 | "TOKEN = \"\" # @param {type:\"string\"}\n",
1812 | "#@markdown Default
username : user
password : pass\n",
1813 | "HOME = os.path.expanduser(\"~\")\n",
1814 | "runW = get_ipython()\n",
1815 | "\n",
1816 | "if not os.path.exists(f\"{HOME}/.ipython/ttmg.py\"):\n",
1817 | " hCode = \"https://raw.githubusercontent.com/biplobsd/\" \\\n",
1818 | " \"Google-Colab-CloudTorrent/master/res/ttmg.py\"\n",
1819 | " urllib.request.urlretrieve(hCode, f\"{HOME}/.ipython/ttmg.py\")\n",
1820 | "\n",
1821 | "if not os.path.exists(\"/root/.ipython/rlab_utils.py\"):\n",
1822 | " from shlex import split as _spl\n",
1823 | " from subprocess import run\n",
1824 | "\n",
1825 | " shellCmd = \"wget -qq https://biplobsd.github.io/RLabClone/res/rlab_utils.py \\\n",
1826 | " -O /root/.ipython/rlab_utils.py\"\n",
1827 | " run(_spl(shellCmd))\n",
1828 | "\n",
1829 | "from ttmg import (\n",
1830 | " runSh,\n",
1831 | " loadingAn,\n",
1832 | " ngrok,\n",
1833 | " displayUrl,\n",
1834 | " findProcess,\n",
1835 | " CWD,\n",
1836 | " textAn,\n",
1837 | " checkAvailable\n",
1838 | ")\n",
1839 | "from rlab_utils import (\n",
1840 | " displayOutput,\n",
1841 | " checkAvailable,\n",
1842 | " prepareSession,\n",
1843 | " PATH_RClone_Config,\n",
1844 | " accessSettingFile,\n",
1845 | " memGiB,\n",
1846 | ")\n",
1847 | "\n",
1848 | "loadingAn()\n",
1849 | "prepareSession()\n",
1850 | "pid = findProcess(\"rclone\", \"rcd\", isPid=True)\n",
1851 | "try:\n",
1852 | " os.kill(int(pid), signal.SIGTERM)\n",
1853 | "except TypeError:\n",
1854 | " pass\n",
1855 | "cmd = \"rclone rcd --rc-web-gui --rc-addr :5572\" \\\n",
1856 | " \" --rc-serve\" \\\n",
1857 | " \" --rc-user=user --rc-pass=pass\" \\\n",
1858 | " \" --rc-no-auth\" \\\n",
1859 | " rf\" --config {PATH_RClone_Config}/rclone.conf\" \\\n",
1860 | " ' --user-agent \"Mozilla\"' \\\n",
1861 | " ' --transfers 16' \\\n",
1862 | " \" &\"\n",
1863 | "runSh(cmd, shell=True)\n",
1864 | "# START_SERVER\n",
1865 | "# Ngrok region 'us','eu','ap','au','sa','jp','in'\n",
1866 | "clear_output()\n",
1867 | "Server = ngrok(\n",
1868 | " TOKEN, USE_FREE_TOKEN, [['rclone', 5572, 'http'],\n",
1869 | " ['filebrowser', 4000, 'http']], 'ap', \n",
1870 | " [f\"{HOME}/.ngrok2/filebrowserRclone.yml\", 4099]\n",
1871 | ").start('rclone', displayB=False)\n",
1872 | "# output\n",
1873 | "clear_output()\n",
1874 | "displayUrl(Server, pNamU='Rclone webUI : ', \n",
1875 | " ExUrl=fr\"http://user:pass@{Server['url'][7:]}\")"
1876 | ],
1877 | "execution_count": 0,
1878 | "outputs": []
1879 | },
1880 | {
1881 | "cell_type": "code",
1882 | "metadata": {
1883 | "id": "-BeHgvH1aNIJ",
1884 | "colab_type": "code",
1885 | "cellView": "form",
1886 | "colab": {}
1887 | },
1888 | "source": [
1889 | "#@markdown Create/Edit Rclone config
Create a new remote with name, type and options.
After created your config file download that. Next time just upload and you are done!\n",
1890 | "import os, urllib.request\n",
1891 | "from IPython.display import HTML\n",
1892 | "USE_FREE_TOKEN = True # @param {type:\"boolean\"}\n",
1893 | "TOKEN = \"\" # @param {type:\"string\"}\n",
1894 | "HOME = os.path.expanduser(\"~\")\n",
1895 | "runW = get_ipython()\n",
1896 | "\n",
1897 | "if not os.path.exists(f\"{HOME}/.ipython/ttmg.py\"):\n",
1898 | " hCode = \"https://raw.githubusercontent.com/biplobsd/\" \\\n",
1899 | " \"Google-Colab-CloudTorrent/master/res/ttmg.py\"\n",
1900 | " urllib.request.urlretrieve(hCode, f\"{HOME}/.ipython/ttmg.py\")\n",
1901 | "\n",
1902 | "#####################################\n",
1903 | "\n",
1904 | "if not os.path.exists(\"/root/.ipython/rlab_utils.py\"):\n",
1905 | " from shlex import split as _spl\n",
1906 | " from subprocess import run\n",
1907 | "\n",
1908 | " shellCmd = \"wget -qq https://biplobsd.github.io/RLabClone/res/rlab_utils.py \\\n",
1909 | " -O /root/.ipython/rlab_utils.py\"\n",
1910 | " run(_spl(shellCmd))\n",
1911 | "\n",
1912 | "from rlab_utils import (\n",
1913 | " prepareSession,\n",
1914 | " PATH_RClone_Config,\n",
1915 | " runSh\n",
1916 | ")\n",
1917 | "from ttmg import (\n",
1918 | " ngrok\n",
1919 | ")\n",
1920 | "\n",
1921 | "###################################\n",
1922 | "import codecs\n",
1923 | "import contextlib\n",
1924 | "import locale\n",
1925 | "import os\n",
1926 | "import pty\n",
1927 | "import select\n",
1928 | "import signal\n",
1929 | "import subprocess\n",
1930 | "import sys\n",
1931 | "import termios\n",
1932 | "import time\n",
1933 | "\n",
1934 | "\n",
1935 | "from IPython.utils import text\n",
1936 | "import six\n",
1937 | "from google.colab import _ipython\n",
1938 | "from google.colab import _message\n",
1939 | "from google.colab.output import _tags\n",
1940 | "\n",
1941 | "# Linux read(2) limits to 0x7ffff000 so stay under that for clarity.\n",
1942 | "_PTY_READ_MAX_BYTES_FOR_TEST = 2**20 # 1MB\n",
1943 | "\n",
1944 | "_ENCODING = 'UTF-8'\n",
1945 | "\n",
1946 | "class ShellResult(object):\n",
1947 | " \"\"\"Result of an invocation of the shell magic.\n",
1948 | "\n",
1949 | " Note: This is intended to mimic subprocess.CompletedProcess, but has slightly\n",
1950 | " different characteristics, including:\n",
1951 | " * CompletedProcess has separate stdout/stderr properties. A ShellResult\n",
1952 | " has a single property containing the merged stdout/stderr stream,\n",
1953 | " providing compatibility with the existing \"!\" shell magic (which this is\n",
1954 | " intended to provide an alternative to).\n",
1955 | " * A custom __repr__ method that returns output. When the magic is invoked as\n",
1956 | " the only statement in the cell, Python prints the string representation by\n",
1957 | " default. The existing \"!\" shell magic also returns output.\n",
1958 | " \"\"\"\n",
1959 | "\n",
1960 | " def __init__(self, args, returncode, command_output):\n",
1961 | " self.args = args\n",
1962 | " self.returncode = returncode\n",
1963 | " self.output = command_output\n",
1964 | "\n",
1965 | " def check_returncode(self):\n",
1966 | " if self.returncode:\n",
1967 | " raise subprocess.CalledProcessError(\n",
1968 | " returncode=self.returncode, cmd=self.args, output=self.output)\n",
1969 | "\n",
1970 | " def _repr_pretty_(self, p, cycle): # pylint:disable=unused-argument\n",
1971 | " # Note: When invoking the magic and not assigning the result\n",
1972 | " # (e.g. %shell echo \"foo\"), Python's default semantics will be used and\n",
1973 | " # print the string representation of the object. By default, this will\n",
1974 | " # display the __repr__ of ShellResult. Suppress this representation since\n",
1975 | " # the output of the command has already been displayed to the output window.\n",
1976 | " if cycle:\n",
1977 | " raise NotImplementedError\n",
1978 | "\n",
1979 | "\n",
1980 | "def _configure_term_settings(pty_fd):\n",
1981 | " term_settings = termios.tcgetattr(pty_fd)\n",
1982 | " # ONLCR transforms NL to CR-NL, which is undesirable. Ensure this is disabled.\n",
1983 | " # http://man7.org/linux/man-pages/man3/termios.3.html\n",
1984 | " term_settings[1] &= ~termios.ONLCR\n",
1985 | "\n",
1986 | " # ECHOCTL echoes control characters, which is undesirable.\n",
1987 | " term_settings[3] &= ~termios.ECHOCTL\n",
1988 | "\n",
1989 | " termios.tcsetattr(pty_fd, termios.TCSANOW, term_settings)\n",
1990 | "\n",
1991 | "\n",
1992 | "def _run_command(cmd, clear_streamed_output):\n",
1993 | " \"\"\"Calls the shell command, forwarding input received on the stdin_socket.\"\"\"\n",
1994 | " locale_encoding = locale.getpreferredencoding()\n",
1995 | " if locale_encoding != _ENCODING:\n",
1996 | " raise NotImplementedError(\n",
1997 | " 'A UTF-8 locale is required. Got {}'.format(locale_encoding))\n",
1998 | "\n",
1999 | " parent_pty, child_pty = pty.openpty()\n",
2000 | " _configure_term_settings(child_pty)\n",
2001 | "\n",
2002 | " epoll = select.epoll()\n",
2003 | " epoll.register(\n",
2004 | " parent_pty,\n",
2005 | " (select.EPOLLIN | select.EPOLLOUT | select.EPOLLHUP | select.EPOLLERR))\n",
2006 | "\n",
2007 | " try:\n",
2008 | " temporary_clearer = _tags.temporary if clear_streamed_output else _no_op\n",
2009 | "\n",
2010 | " with temporary_clearer(), _display_stdin_widget(\n",
2011 | " delay_millis=500) as update_stdin_widget:\n",
2012 | " # TODO(b/115531839): Ensure that subprocesses are terminated upon\n",
2013 | " # interrupt.\n",
2014 | " p = subprocess.Popen(\n",
2015 | " cmd,\n",
2016 | " shell=True,\n",
2017 | " executable='/bin/bash',\n",
2018 | " stdout=child_pty,\n",
2019 | " stdin=child_pty,\n",
2020 | " stderr=child_pty,\n",
2021 | " close_fds=True)\n",
2022 | " # The child PTY is only needed by the spawned process.\n",
2023 | " os.close(child_pty)\n",
2024 | "\n",
2025 | " return _monitor_process(parent_pty, epoll, p, cmd, update_stdin_widget)\n",
2026 | " finally:\n",
2027 | " epoll.close()\n",
2028 | " os.close(parent_pty)\n",
2029 | "\n",
2030 | "\n",
2031 | "class _MonitorProcessState(object):\n",
2032 | "\n",
2033 | " def __init__(self):\n",
2034 | " self.process_output = six.StringIO()\n",
2035 | " self.is_pty_still_connected = True\n",
2036 | "\n",
2037 | "\n",
2038 | "def _monitor_process(parent_pty, epoll, p, cmd, update_stdin_widget):\n",
2039 | " \"\"\"Monitors the given subprocess until it terminates.\"\"\"\n",
2040 | " state = _MonitorProcessState()\n",
2041 | "\n",
2042 | " # A single UTF-8 character can span multiple bytes. os.read returns bytes and\n",
2043 | " # could return a partial byte sequence for a UTF-8 character. Using an\n",
2044 | " # incremental decoder is incrementally fed input bytes and emits UTF-8\n",
2045 | " # characters.\n",
2046 | " decoder = codecs.getincrementaldecoder(_ENCODING)()\n",
2047 | "\n",
2048 | " num_interrupts = 0\n",
2049 | " echo_status = None\n",
2050 | " while True:\n",
2051 | " try:\n",
2052 | " result = _poll_process(parent_pty, epoll, p, cmd, decoder, state)\n",
2053 | " if result is not None:\n",
2054 | " return result\n",
2055 | " term_settings = termios.tcgetattr(parent_pty)\n",
2056 | " new_echo_status = bool(term_settings[3] & termios.ECHO)\n",
2057 | " if echo_status != new_echo_status:\n",
2058 | " update_stdin_widget(new_echo_status)\n",
2059 | " echo_status = new_echo_status\n",
2060 | " except KeyboardInterrupt:\n",
2061 | " try:\n",
2062 | " num_interrupts += 1\n",
2063 | " if num_interrupts == 1:\n",
2064 | " p.send_signal(signal.SIGINT)\n",
2065 | " elif num_interrupts == 2:\n",
2066 | " # Process isn't responding to SIGINT and user requested another\n",
2067 | " # interrupt. Attempt to send SIGTERM followed by a SIGKILL if the\n",
2068 | " # process doesn't respond.\n",
2069 | " p.send_signal(signal.SIGTERM)\n",
2070 | " time.sleep(0.5)\n",
2071 | " if p.poll() is None:\n",
2072 | " p.send_signal(signal.SIGKILL)\n",
2073 | " except KeyboardInterrupt:\n",
2074 | " # Any interrupts that occur during shutdown should not propagate.\n",
2075 | " pass\n",
2076 | "\n",
2077 | " if num_interrupts > 2:\n",
2078 | " # In practice, this shouldn't be possible since\n",
2079 | " # SIGKILL is quite effective.\n",
2080 | " raise\n",
2081 | "\n",
2082 | "\n",
2083 | "def _poll_process(parent_pty, epoll, p, cmd, decoder, state):\n",
2084 | " \"\"\"Polls the process and captures / forwards input and output.\"\"\"\n",
2085 | "\n",
2086 | " terminated = p.poll() is not None\n",
2087 | " if terminated:\n",
2088 | " termios.tcdrain(parent_pty)\n",
2089 | " # We're no longer interested in write events and only want to consume any\n",
2090 | " # remaining output from the terminated process. Continuing to watch write\n",
2091 | " # events may cause early termination of the loop if no output was\n",
2092 | " # available but the pty was ready for writing.\n",
2093 | " epoll.modify(parent_pty,\n",
2094 | " (select.EPOLLIN | select.EPOLLHUP | select.EPOLLERR))\n",
2095 | "\n",
2096 | " output_available = False\n",
2097 | "\n",
2098 | " events = epoll.poll()\n",
2099 | " input_events = []\n",
2100 | " for _, event in events:\n",
2101 | " if event & select.EPOLLIN:\n",
2102 | " output_available = True\n",
2103 | " raw_contents = os.read(parent_pty, _PTY_READ_MAX_BYTES_FOR_TEST)\n",
2104 | " import re\n",
2105 | " decoded_contents = re.sub(r\"http:\\/\\/127.0.0.1:53682\", Server[\"url\"], \n",
2106 | " decoder.decode(raw_contents))\n",
2107 | " sys.stdout.write(decoded_contents)\n",
2108 | " state.process_output.write(decoded_contents)\n",
2109 | "\n",
2110 | " if event & select.EPOLLOUT:\n",
2111 | " # Queue polling for inputs behind processing output events.\n",
2112 | " input_events.append(event)\n",
2113 | "\n",
2114 | " # PTY was disconnected or encountered a connection error. In either case,\n",
2115 | " # no new output should be made available.\n",
2116 | " if (event & select.EPOLLHUP) or (event & select.EPOLLERR):\n",
2117 | " state.is_pty_still_connected = False\n",
2118 | "\n",
2119 | " for event in input_events:\n",
2120 | " # Check to see if there is any input on the stdin socket.\n",
2121 | " # pylint: disable=protected-access\n",
2122 | " input_line = _message._read_stdin_message()\n",
2123 | " # pylint: enable=protected-access\n",
2124 | " if input_line is not None:\n",
2125 | " # If a very large input or sequence of inputs is available, it's\n",
2126 | " # possible that the PTY buffer could be filled and this write call\n",
2127 | " # would block. To work around this, non-blocking writes and keeping\n",
2128 | " # a list of to-be-written inputs could be used. Empirically, the\n",
2129 | " # buffer limit is ~12K, which shouldn't be a problem in most\n",
2130 | " # scenarios. As such, optimizing for simplicity.\n",
2131 | " input_bytes = bytes(input_line.encode(_ENCODING))\n",
2132 | " os.write(parent_pty, input_bytes)\n",
2133 | "\n",
2134 | " # Once the process is terminated, there still may be output to be read from\n",
2135 | " # the PTY. Wait until the PTY has been disconnected and no more data is\n",
2136 | " # available for read. Simply waiting for disconnect may be insufficient if\n",
2137 | " # there is more data made available on the PTY than we consume in a single\n",
2138 | " # read call.\n",
2139 | " if terminated and not state.is_pty_still_connected and not output_available:\n",
2140 | " sys.stdout.flush()\n",
2141 | " command_output = state.process_output.getvalue()\n",
2142 | " return ShellResult(cmd, p.returncode, command_output)\n",
2143 | "\n",
2144 | " if not output_available:\n",
2145 | " # The PTY is almost continuously available for reading input to provide\n",
2146 | " # to the underlying subprocess. This means that the polling loop could\n",
2147 | " # effectively become a tight loop and use a large amount of CPU. Add a\n",
2148 | " # slight delay to give resources back to the system while monitoring the\n",
2149 | " # process.\n",
2150 | " # Skip this delay if we read output in the previous loop so that a partial\n",
2151 | " # read doesn't unnecessarily sleep before reading more output.\n",
2152 | " # TODO(b/115527726): Rather than sleep, poll for incoming messages from\n",
2153 | " # the frontend in the same poll as for the output.\n",
2154 | " time.sleep(0.1)\n",
2155 | "\n",
2156 | "\n",
2157 | "@contextlib.contextmanager\n",
2158 | "def _display_stdin_widget(delay_millis=0):\n",
2159 | " \"\"\"Context manager that displays a stdin UI widget and hides it upon exit.\n",
2160 | "\n",
2161 | " Args:\n",
2162 | " delay_millis: Duration (in milliseconds) to delay showing the widget within\n",
2163 | " the UI.\n",
2164 | "\n",
2165 | " Yields:\n",
2166 | " A callback that can be invoked with a single argument indicating whether\n",
2167 | " echo is enabled.\n",
2168 | " \"\"\"\n",
2169 | " shell = _ipython.get_ipython()\n",
2170 | " display_args = ['cell_display_stdin', {'delayMillis': delay_millis}]\n",
2171 | " _message.blocking_request(*display_args, parent=shell.parent_header)\n",
2172 | "\n",
2173 | " def echo_updater(new_echo_status):\n",
2174 | " # Note: Updating the echo status uses colab_request / colab_reply on the\n",
2175 | " # stdin socket. Input provided by the user also sends messages on this\n",
2176 | " # socket. If user input is provided while the blocking_request call is still\n",
2177 | " # waiting for a colab_reply, the input will be dropped per\n",
2178 | " # https://github.com/googlecolab/colabtools/blob/56e4dbec7c4fa09fad51b60feb5c786c69d688c6/google/colab/_message.py#L100.\n",
2179 | " update_args = ['cell_update_stdin', {'echo': new_echo_status}]\n",
2180 | " _message.blocking_request(*update_args, parent=shell.parent_header)\n",
2181 | "\n",
2182 | " yield echo_updater\n",
2183 | "\n",
2184 | " hide_args = ['cell_remove_stdin', {}]\n",
2185 | " _message.blocking_request(*hide_args, parent=shell.parent_header)\n",
2186 | "\n",
2187 | "\n",
2188 | "@contextlib.contextmanager\n",
2189 | "def _no_op():\n",
2190 | " yield\n",
2191 | "\n",
2192 | "###################################\n",
2193 | "prepareSession()\n",
2194 | "\n",
2195 | "Server = ngrok(\n",
2196 | " TOKEN, USE_FREE_TOKEN, [['rcloneConfig', 53682, 'http'], \n",
2197 | " ['pyload', 8000, 'http']], 'sa', \n",
2198 | " [f\"{HOME}/.ngrok2/rclonePyload.yml\", 4074]\n",
2199 | ").start('rcloneConfig', displayB=False, v=False)\n",
2200 | "\n",
2201 | "printData = \"\"\"Copy this URL,\n",
2202 | " It's needed for authentication purposes.\n",
2203 | " After completing your account select, you redirect to a website, after back\n",
2204 | " you need to change http://127.0.0.0:53682 to {}\"\"\".format(Server['url'])\n",
2205 | "print(printData)\n",
2206 | "display(HTML(' See how
'))\n",
2207 | "print(f\"{Server['url']}\", end=\"\\n\\n\")\n",
2208 | "_run_command(f\"rclone config --config {PATH_RClone_Config}/rclone.conf\", False)"
2209 | ],
2210 | "execution_count": 0,
2211 | "outputs": []
2212 | },
2213 | {
2214 | "cell_type": "code",
2215 | "metadata": {
2216 | "id": "uB-vkVstVpVs",
2217 | "colab_type": "code",
2218 | "cellView": "form",
2219 | "colab": {}
2220 | },
2221 | "source": [
2222 | "# ============================= FORM ============================= #\n",
2223 | "# @markdown #### ← Execute Upload Local File\n",
2224 | "MODE = \"RCONFIG\" # @param ['UTILS', 'RCONFIG', 'RCONFIG_append', \"GENERATELIST\"]\n",
2225 | "REMOTE = \"mnc\" # @param {type:\"string\"}\n",
2226 | "QUERY_PATTERN = \"\" # @param {type:\"string\"}\n",
2227 | "# @markdown #### For not able to upload local file : https://stackoverflow.com/a/58661947\n",
2228 | "# ================================================================ #\n",
2229 | "\n",
2230 | "from os import path as _p\n",
2231 | "\n",
2232 | "if not _p.exists(\"/root/.ipython/rlab_utils.py\"):\n",
2233 | " from shlex import split as _spl\n",
2234 | " from subprocess import run # nosec\n",
2235 | "\n",
2236 | " shellCmd = \"wget -qq https://biplobsd.github.io/RLabClone/res/rlab_utils.py \\\n",
2237 | " -O /root/.ipython/rlab_utils.py\"\n",
2238 | " run(_spl(shellCmd)) # nosec\n",
2239 | "\n",
2240 | "import importlib, rlab_utils\n",
2241 | "from google.colab import files # pylint: disable=import-error #nosec\n",
2242 | "from rlab_utils import checkAvailable, runSh, PATH_RClone_Config, prepareSession\n",
2243 | "\n",
2244 | "\n",
2245 | "def generateUploadList():\n",
2246 | " prepareSession()\n",
2247 | " if checkAvailable(\"/content/upload.txt\"):\n",
2248 | " runSh(\"rm -f upload.txt\")\n",
2249 | " runSh(\n",
2250 | " f\"rclone --config {PATH_RClone_Config}/rclone.conf lsf {REMOTE}: --include '{QUERY_PATTERN}' --drive-shared-with-me --files-only --max-depth 1 > /content/upload.txt\",\n",
2251 | " shell=True, # nosec\n",
2252 | " )\n",
2253 | "\n",
2254 | "\n",
2255 | "def uploadLocalFiles():\n",
2256 | " prepareSession()\n",
2257 | " if MODE == \"UTILS\":\n",
2258 | " filePath = \"/root/.ipython/rlab_utils.py\"\n",
2259 | " elif MODE in (\"RCONFIG\", \"RCONFIG_append\"):\n",
2260 | " filePath = f\"{PATH_RClone_Config}/rclone.conf\"\n",
2261 | " else:\n",
2262 | " pass\n",
2263 | "\n",
2264 | " try:\n",
2265 | " if checkAvailable(filePath):\n",
2266 | " runSh(f\"rm -f {filePath}\")\n",
2267 | " print(\"Select file from your computer.\\n\")\n",
2268 | " uploadedFile = files.upload()\n",
2269 | " fileNameDictKeys = uploadedFile.keys()\n",
2270 | " fileNo = len(fileNameDictKeys)\n",
2271 | " if fileNo > 1:\n",
2272 | " for fn in fileNameDictKeys:\n",
2273 | " runSh(f'rm -f \"/content/{fn}\"')\n",
2274 | " return print(\"\\nPlease only upload a single config file.\")\n",
2275 | " elif fileNo == 0:\n",
2276 | " return print(\"\\nFile upload cancelled.\")\n",
2277 | " elif fileNo == 1:\n",
2278 | " for fn in fileNameDictKeys:\n",
2279 | " if checkAvailable(f\"/content/{fn}\"):\n",
2280 | " if MODE == \"RCONFIG_append\":\n",
2281 | " import urllib\n",
2282 | " urllib.request.urlretrieve(\"https://biplobsd.github.io/RLabClone/res/rclonelab/rclone.conf\",\n",
2283 | " \"/usr/local/sessionSettings/rclone.conf\")\n",
2284 | " with open(f\"/content/{fn}\", 'r+') as r:\n",
2285 | " new_data = r.read()\n",
2286 | " runSh(f'rm -f \"/content/{fn}\"')\n",
2287 | " with open(filePath, 'r+') as f:\n",
2288 | " old_data = f.read()\n",
2289 | " f.seek(0)\n",
2290 | " f.truncate(0)\n",
2291 | " f.write(old_data + new_data)\n",
2292 | " print(\"\\nUpdate completed.\")\n",
2293 | " else:\n",
2294 | " runSh(f'mv -f \"/content/{fn}\" {filePath}')\n",
2295 | " runSh(f\"chmod 666 {filePath}\")\n",
2296 | " runSh(f'rm -f \"/content/{fn}\"')\n",
2297 | " importlib.reload(rlab_utils)\n",
2298 | " print(\"\\nUpload completed.\")\n",
2299 | " return\n",
2300 | " else:\n",
2301 | " print(\"\\nNo file\")\n",
2302 | " return\n",
2303 | " except:\n",
2304 | " return print(\"\\nUpload process Error.\")\n",
2305 | "\n",
2306 | "\n",
2307 | "if MODE == \"GENERATELIST\":\n",
2308 | " generateUploadList()\n",
2309 | "else:\n",
2310 | " uploadLocalFiles()\n"
2311 | ],
2312 | "execution_count": 0,
2313 | "outputs": []
2314 | },
2315 | {
2316 | "cell_type": "code",
2317 | "metadata": {
2318 | "id": "RG2o5dgK5P4j",
2319 | "colab_type": "code",
2320 | "cellView": "form",
2321 | "colab": {}
2322 | },
2323 | "source": [
2324 | "# ============================= FORM ============================= #\n",
2325 | "# @markdown #### ← Download config file.\n",
2326 | "MODE = \"RCONFIG\" # @param ['UTILS', 'RCONFIG']\n",
2327 | "# ================================================================ #\n",
2328 | "from google.colab import files\n",
2329 | "\n",
2330 | "def downloadFile():\n",
2331 | " if MODE == \"UTILS\":\n",
2332 | " filePath = \"/root/.ipython/rlab_utils.py\"\n",
2333 | " elif MODE == \"RCONFIG\":\n",
2334 | " filePath = f\"{PATH_RClone_Config}/rclone.conf\"\n",
2335 | " else:\n",
2336 | " pass\n",
2337 | " try:\n",
2338 | " files.download(filePath)\n",
2339 | " except FileNotFoundError:\n",
2340 | " print(\"File not found!\")\n",
2341 | "\n",
2342 | "if __name__ == \"__main__\":\n",
2343 | " downloadFile()\n"
2344 | ],
2345 | "execution_count": 0,
2346 | "outputs": []
2347 | },
2348 | {
2349 | "cell_type": "markdown",
2350 | "metadata": {
2351 | "id": "cHTe9qp2E6f5",
2352 | "colab_type": "text"
2353 | },
2354 | "source": [
2355 | "# **10**. NZBget\n",
2356 | "# 
"
2357 | ]
2358 | },
2359 | {
2360 | "cell_type": "code",
2361 | "metadata": {
2362 | "id": "UinZqhU6XBKF",
2363 | "colab_type": "code",
2364 | "cellView": "form",
2365 | "colab": {}
2366 | },
2367 | "source": [
2368 | "#@markdown ← Click Here to Use NZBget (ngrok)
\n",
2369 | "Ngrok_Token = \"\" #@param {type:\"string\"}\n",
2370 | "\n",
2371 | "import os, psutil, uuid, time, urllib.request, json; from IPython.display import clear_output\n",
2372 | "import ipywidgets as widgets\n",
2373 | "from IPython.display import HTML, clear_output\n",
2374 | "from google.colab import output\n",
2375 | "\n",
2376 | "class MakeButton(object):\n",
2377 | " def __init__(self, title, callback):\n",
2378 | " self._title = title\n",
2379 | " self._callback = callback\n",
2380 | " def _repr_html_(self):\n",
2381 | " callback_id = 'button-' + str(uuid.uuid4())\n",
2382 | " output.register_callback(callback_id, self._callback)\n",
2383 | " template = \"\"\"\n",
2384 | " \"\"\"\n",
2390 | " html = template.format(title=self._title, callback_id=callback_id)\n",
2391 | " return html\n",
2392 | " \n",
2393 | "def MakeLabel(description, button_style):\n",
2394 | " return widgets.Button(description=description, disabled=True, button_style=button_style)\n",
2395 | "\n",
2396 | "if os.path.isfile(\"/usr/local/bin/ngrok\") == False:\n",
2397 | " !wget -q -c -nc https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip\n",
2398 | " !unzip -qq -n ngrok-stable-linux-amd64.zip\n",
2399 | " !mv ngrok /usr/local/bin/ngrok\n",
2400 | " !rm -f /content/ngrok-stable-linux-amd64.zip\n",
2401 | " print(\"ngrok successfully installed.\")\n",
2402 | " clear_output(wait=True)\n",
2403 | "else:\n",
2404 | " print(\"ngrok already installed. Skipping... \")\n",
2405 | " clear_output(wait=True)\n",
2406 | " !pkill ngrok\n",
2407 | "\n",
2408 | "def RandomGenerator():\n",
2409 | " return time.strftime(\"%S\") + str(time.time()).split(\".\")[-1]\n",
2410 | "\n",
2411 | "def CheckProcess(process, command):\n",
2412 | " for pid in psutil.pids():\n",
2413 | " try:\n",
2414 | " p = psutil.Process(pid)\n",
2415 | " if process in p.name():\n",
2416 | " for arg in p.cmdline():\n",
2417 | " if command in str(arg): \n",
2418 | " return True\n",
2419 | " else:\n",
2420 | " pass\n",
2421 | " else:\n",
2422 | " pass\n",
2423 | " except:\n",
2424 | " continue\n",
2425 | "\n",
2426 | "try:\n",
2427 | " try:\n",
2428 | " Random_NumberNZ\n",
2429 | " except NameError:\n",
2430 | " Random_NumberNZ = RandomGenerator()\n",
2431 | " display(MakeLabel('Installing in Progress', 'warning'))\n",
2432 | " if os.path.isfile(\"/content/nzbget/nzbget\") == False:\n",
2433 | " !mkdir /content/nzbget\n",
2434 | " get_ipython().system_raw(\"rm -rf /content/sample_data/ && wget https://nzbget.net/download/nzbget-latest-bin-linux.run && sh nzbget-latest-bin-linux.run\")\n",
2435 | " if CheckProcess(\"nzbget\", \"\") != True:\n",
2436 | " get_ipython().system_raw(\"/content/nzbget/nzbget -s &\")\n",
2437 | "except:\n",
2438 | " clear_output(wait=True)\n",
2439 | "\n",
2440 | "get_ipython().system_raw('/usr/local/bin/ngrok authtoken $Ngrok_Token && /usr/local/bin/ngrok http 6789 &')\n",
2441 | "time.sleep(10)\n",
2442 | "clear_output(wait=True)\n",
2443 | "with urllib.request.urlopen('http://localhost:4040/api/tunnels') as response:\n",
2444 | " data = json.loads(response.read().decode())\n",
2445 | " host = data['tunnels'][0]['public_url'][8:]\n",
2446 | " print(f'Open this link in new tab http://{host}')"
2447 | ],
2448 | "execution_count": 0,
2449 | "outputs": []
2450 | },
2451 | {
2452 | "cell_type": "markdown",
2453 | "metadata": {
2454 | "id": "kAdRu4gm5k8v",
2455 | "colab_type": "text"
2456 | },
2457 | "source": [
2458 | "# **11**. 7-Zip + UNRAR\n",
2459 | "
"
2460 | ]
2461 | },
2462 | {
2463 | "cell_type": "code",
2464 | "metadata": {
2465 | "id": "MXv72l138scn",
2466 | "colab_type": "code",
2467 | "cellView": "form",
2468 | "colab": {}
2469 | },
2470 | "source": [
2471 | "#@markdown ← Required: Install 7-Zip + UNRAR\n",
2472 | "!sudo apt update\n",
2473 | "!sudo apt install p7zip-full p7zip-rar unrar rar"
2474 | ],
2475 | "execution_count": 0,
2476 | "outputs": []
2477 | },
2478 | {
2479 | "cell_type": "code",
2480 | "metadata": {
2481 | "colab_type": "code",
2482 | "cellView": "form",
2483 | "id": "VjDJz38G9fqo",
2484 | "colab": {}
2485 | },
2486 | "source": [
2487 | "#@markdown » Run to change current working directory\n",
2488 | "import os\n",
2489 | "new_dir = \"\" #@param {type:\"string\"}\n",
2490 | "\n",
2491 | "%cd \"$new_dir\""
2492 | ],
2493 | "execution_count": 0,
2494 | "outputs": []
2495 | },
2496 | {
2497 | "cell_type": "code",
2498 | "metadata": {
2499 | "id": "QTmQKpsm8fFQ",
2500 | "colab_type": "code",
2501 | "cellView": "form",
2502 | "colab": {}
2503 | },
2504 | "source": [
2505 | "#@title » Extract Archive (.zip, .rar, .7z, etc.)\n",
2506 | "import os, sys, re\n",
2507 | "\n",
2508 | "archive_file_path = \"\" #@param {type:\"string\"}\n",
2509 | "os.environ['inputFile'] = archive_file_path\n",
2510 | "\n",
2511 | "!7z e \"$inputFile\""
2512 | ],
2513 | "execution_count": 0,
2514 | "outputs": []
2515 | },
2516 | {
2517 | "cell_type": "code",
2518 | "metadata": {
2519 | "colab_type": "code",
2520 | "cellView": "form",
2521 | "id": "pWKlqyFP_qkX",
2522 | "colab": {}
2523 | },
2524 | "source": [
2525 | "#@title » Create .zip from Folder\n",
2526 | "import os, sys, re\n",
2527 | "\n",
2528 | "folder_path = \"\" #@param {type:\"string\"}\n",
2529 | "\n",
2530 | "output_file_path = re.search(\"^[\\/].+\\/\", folder_path)\n",
2531 | "output_file_path_raw = output_file_path.group(0)\n",
2532 | "delsplit = re.search(\"\\/(?:.(?!\\/))+$\", folder_path)\n",
2533 | "folder_name = re.sub(\"^[\\/]\", \"\", delsplit.group(0))\n",
2534 | "\n",
2535 | "os.environ['inputDir'] = folder_path\n",
2536 | "os.environ['outputPath'] = output_file_path_raw\n",
2537 | "os.environ['folderName'] = folder_name\n",
2538 | "\n",
2539 | "!7z a -tzip \"$outputPath\"/\"$folderName\".zip \"$inputDir\""
2540 | ],
2541 | "execution_count": 0,
2542 | "outputs": []
2543 | }
2544 | ]
2545 | }
--------------------------------------------------------------------------------