├── HandBrakeCLI_Colab.ipynb └── README.md /HandBrakeCLI_Colab.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "name": "HandyCLI.ipynb", 7 | "private_outputs": true, 8 | "provenance": [], 9 | "collapsed_sections": [ 10 | "pCPualPTTLMa", 11 | "a4TZEfjtSF5C", 12 | "a9Zjw2QUTP1A", 13 | "pOJeymyOQzvr" 14 | ] 15 | }, 16 | "kernelspec": { 17 | "name": "python3", 18 | "display_name": "Python 3" 19 | } 20 | }, 21 | "cells": [ 22 | { 23 | "cell_type": "markdown", 24 | "metadata": { 25 | "id": "Bo8JdYqmmUA0" 26 | }, 27 | "source": [ 28 | "#
\"Contact\"Github\"/
\n", 29 | "
\"Hits\"
\n", 30 | "

HandBrakeCLI-ColabNotebook v1.3

\n", 31 | "\n", 32 | "Convert/Compress videos using HandBrake in colab.\n", 33 | "\n", 34 | "Give a like and follow 😊" 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": { 40 | "id": "0EbCdnXG3b_P" 41 | }, 42 | "source": [ 43 | "# GOOGLE DRIVE" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "metadata": { 49 | "id": "eYSZh4dJ2D8q", 50 | "cellView": "form" 51 | }, 52 | "source": [ 53 | "#@title
Mount Google Drive
\n", 54 | "#@markdown
\"Icon\"\n", 55 | "#@markdown
Use this if and only if you don't use rclone yet.
\n", 56 | "#@markdown This may lead to corrupt output file sometimes.\n", 57 | "from google.colab import drive\n", 58 | "drive.mount('/content/drive')" 59 | ], 60 | "execution_count": null, 61 | "outputs": [] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": { 66 | "id": "pCPualPTTLMa" 67 | }, 68 | "source": [ 69 | "#Run These first" 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "metadata": { 75 | "id": "BuvdTmE_Ersm", 76 | "cellView": "form" 77 | }, 78 | "source": [ 79 | "#@title <<----Install HandBrake and rClone\n", 80 | "%%capture\n", 81 | "AUTO_RECONNECT = True #@param {type:\"boolean\"}\n", 82 | "HANDBRAKE = True #@param {type:\"boolean\"}\n", 83 | "RCLONE = True #@param {type:\"boolean\"}\n", 84 | "#@markdown Check AUTO_RECONNECT to prevent notebook from disconnecting!\n", 85 | "\n", 86 | "from os import makedirs\n", 87 | "makedirs(\"/content/temp/HandbrakeTemp\", exist_ok = True)\n", 88 | "makedirs(\"/root/.config/rclone\", exist_ok = True) \n", 89 | "if HANDBRAKE==True:\n", 90 | " !wget -qq https://github.com/vot/ffbinaries-prebuilt/releases/download/v4.2.1/ffmpeg-4.2.1-linux-64.zip \n", 91 | " !rm -f ffmpeg-4.2.1-linux-64.zip\n", 92 | " !add-apt-repository ppa:stebbins/handbrake-releases -y \n", 93 | " !apt-get install -y handbrake-cli \n", 94 | " \n", 95 | "if RCLONE==True:\n", 96 | " !curl https://rclone.org/install.sh | sudo bash\n", 97 | "\n", 98 | "if AUTO_RECONNECT:\n", 99 | " import IPython\n", 100 | " from google.colab import output\n", 101 | "\n", 102 | " display(IPython.display.Javascript('''\n", 103 | " function ClickConnect(){\n", 104 | " btn = document.querySelector(\"colab-connect-button\")\n", 105 | " if (btn != null){\n", 106 | " console.log(\"Click colab-connect-button\"); \n", 107 | " btn.click() \n", 108 | " }\n", 109 | " \n", 110 | " btn = document.getElementById('ok')\n", 111 | " if (btn != null){\n", 112 | " console.log(\"Click reconnect\"); \n", 113 | " btn.click() \n", 114 | " }\n", 115 | " }\n", 116 | " \n", 117 | " setInterval(ClickConnect,60000)\n", 118 | " '''))" 119 | ], 120 | "execution_count": null, 121 | "outputs": [] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "metadata": { 126 | "id": "J-S7hYTzLpZK", 127 | "cellView": "form" 128 | }, 129 | "source": [ 130 | "#@title <-----Upload your Rclone.config file\n", 131 | "def moveConfig():\n", 132 | " !mv rclone.conf /root/.config/rclone/rclone.conf\n", 133 | "\n", 134 | "from google.colab import files\n", 135 | "\n", 136 | "uploaded = files.upload()\n", 137 | "\n", 138 | "for fn in uploaded.keys():\n", 139 | " print('User uploaded file \"{name}\" with length {length} bytes'.format(\n", 140 | " name=fn, length=len(uploaded[fn])))\n", 141 | "moveConfig()\n", 142 | "print(\"Moved rclone.conf to /root/.config/rclone/rclone.conf\")" 143 | ], 144 | "execution_count": null, 145 | "outputs": [] 146 | }, 147 | { 148 | "cell_type": "markdown", 149 | "metadata": { 150 | "id": "a4TZEfjtSF5C" 151 | }, 152 | "source": [ 153 | "#
Rclone Mount/Unmount/Copy
\n", 154 | "
\"rclone
" 155 | ] 156 | }, 157 | { 158 | "cell_type": "code", 159 | "metadata": { 160 | "id": "st8Q_ZN27ovN", 161 | "cellView": "form" 162 | }, 163 | "source": [ 164 | "#@markdown

Rclone MOUNT / UNMOUNT

Mount the remote as file system on a mountpoint.
\n", 165 | "import os\n", 166 | "from IPython.display import HTML, clear_output\n", 167 | "import uuid\n", 168 | "import ipywidgets as widgets\n", 169 | "from google.colab import output\n", 170 | "import re\n", 171 | "##########################################\n", 172 | "\n", 173 | "class MakeButton(object):\n", 174 | " def __init__(self, title, callback, style):\n", 175 | " self._title = title\n", 176 | " self._callback = callback\n", 177 | " self._style = style\n", 178 | " def _repr_html_(self):\n", 179 | " callback_id = 'button-' + str(uuid.uuid4())\n", 180 | " output.register_callback(callback_id, self._callback)\n", 181 | " if self._style != \"\":\n", 182 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button mod-\" + self._style\n", 183 | " else:\n", 184 | " style_html = \"p-Widget jupyter-widgets jupyter-button widget-button\"\n", 185 | " template = \"\"\"\n", 186 | " \"\"\"\n", 192 | " html = template.format(title=self._title, callback_id=callback_id, style_html=style_html)\n", 193 | " return html\n", 194 | " \n", 195 | "def ShowAC():\n", 196 | " clear_output(wait=True)\n", 197 | " display(\n", 198 | " widgets.HBox(\n", 199 | " [widgets.VBox(\n", 200 | " [widgets.HTML(\n", 201 | " '''

\n", 202 | " Rclone available config...

\n", 203 | " '''\n", 204 | " ),\n", 205 | " mountNam]\n", 206 | " )\n", 207 | " ]\n", 208 | " )\n", 209 | " )\n", 210 | " \n", 211 | " display(HTML(\"
\"), MakeButton(\"Mount\", MountCMD, \"primary\"),\n", 212 | " MakeButton(\"Unmount\", unmountCMD, \"danger\"))\n", 213 | "content = open(\"/root/.config/rclone/rclone.conf\").read()\n", 214 | "avCon = re.findall(r\"^\\[(.+)\\]$\", content, re.M)\n", 215 | "mountNam = widgets.Dropdown(options=avCon)\n", 216 | "cache_path=\"/content/temp/rCloneTemp\"\n", 217 | "def MountCMD():\n", 218 | " mPoint = f\"/content/drives/{mountNam.value}\"\n", 219 | " os.makedirs(mPoint, exist_ok=True)\n", 220 | " !rclone mount $mountNam.value: $mPoint --user-agent 'Mozilla' --buffer-size 256M --transfers 10 --vfs-cache-mode minimal --vfs-read-chunk-size 500M --vfs-cache-max-size 50G --vfs-cache-max-age 0h0m1s --vfs-cache-poll-interval 0m1s --cache-dir '/content/temp/rCloneTemp' --allow-other --daemon \n", 221 | "\n", 222 | " if os.path.isdir(mPoint)== True:\n", 223 | " print(f\"Mount success! - \\t{mPoint}\")\n", 224 | " else:\n", 225 | " print(f\"Mount failed! - \\t{mPoint}\")\n", 226 | "\n", 227 | "def unmountCMD():\n", 228 | " mPoint = f\"/content/drives/{mountNam.value}\"\n", 229 | " if os.system(f\"fusermount -uz {mPoint}\") == 0:\n", 230 | " runSh(f\"rm -r {mPoint}\")\n", 231 | " print(f\"Unmounted success! - \\t{mPoint}\")\n", 232 | " else:\n", 233 | " runSh(f\"fusermount -uz {mPoint}\", output=True)\n", 234 | "\n", 235 | "ShowAC()" 236 | ], 237 | "execution_count": null, 238 | "outputs": [] 239 | }, 240 | { 241 | "cell_type": "code", 242 | "metadata": { 243 | "id": "EiHlpwVDOjhx", 244 | "cellView": "form" 245 | }, 246 | "source": [ 247 | " \n", 248 | "#@markdown
\"rclone
\n", 249 | " \n", 250 | "#@markdown ---\n", 251 | "source = \"\" #@param {type:\"string\"}\n", 252 | "destination = \"\" #@param {type:\"string\"}\n", 253 | "mode = \"copy\" #@param [\"copy\", \"check\"]\n", 254 | "dry_run = False #@param {type:\"boolean\"}\n", 255 | "Extra_args = \"\" #@param {type:\"string\"}\n", 256 | "#@markdown ---\n", 257 | "Email_notification = False #@param {type:\"boolean\"}\n", 258 | "logs = False #@param {type:\"boolean\"}\n", 259 | "emailID = \"\" #@param {type:\"string\"}\n", 260 | "password = \"\" #@param {type:\"string\"}\n", 261 | "Receiver_ID = \"\" #@param {type:\"string\"}\n", 262 | "#@markdown ---\n", 263 | "import smtplib \n", 264 | "########################################\n", 265 | "args = \"--transfers 20 --checkers 20 --stats-one-line --stats=5s -v --tpslimit 95 --tpslimit-burst 40 \"\n", 266 | "if mode == \"check\":\n", 267 | " args += \"--one-way \"\n", 268 | "if dry_run == True:\n", 269 | " args +=\" --dry-run \"\n", 270 | "if logs == True:\n", 271 | " args += \" --log-file rClone_log.txt \"\n", 272 | "if Extra_args != \"\":\n", 273 | " args +=Extra_args\n", 274 | "######################################\n", 275 | "def runrClone():\n", 276 | " !rclone --user-agent \"Mozilla\" \"$mode\" \"$source\" \"$destination\" $args\n", 277 | " \n", 278 | "def checkEmail():\n", 279 | " if (Email_notification == True and logs == False):\n", 280 | " print(\"You will receive only a notification after task has finished.\")\n", 281 | " runrClone()\n", 282 | " #Send only notification\n", 283 | " \n", 284 | " s = smtplib.SMTP('smtp.gmail.com', 587) \n", 285 | " s.starttls() \n", 286 | " s.login(emailID , password)\n", 287 | " message = \"Your rClone task has Completed!\"\n", 288 | " s.sendmail(emailID, Receiver_ID, message)\n", 289 | " print(\"Email Alert Sent!\") \n", 290 | " s.quit()\n", 291 | " elif (Email_notification == True and logs == True):\n", 292 | " print(\"You will receive a notification with log attached after task has finished.\")\n", 293 | " runrClone()\n", 294 | " #Sending email notification with logs\n", 295 | " \n", 296 | " from email.mime.multipart import MIMEMultipart \n", 297 | " from email.mime.text import MIMEText \n", 298 | " from email.mime.base import MIMEBase \n", 299 | " from email import encoders \n", 300 | "\n", 301 | " fromaddr = emailID\n", 302 | " toaddr = Receiver_ID\n", 303 | " msg = MIMEMultipart() \n", 304 | " # storing the senders email address \n", 305 | " msg['From'] = fromaddr \n", 306 | " # storing the receivers email address \n", 307 | " msg['To'] = toaddr \n", 308 | " # storing the subject \n", 309 | " msg['Subject'] = \"Colab has Finished Running your Cell\"\n", 310 | " # string to store the body of the mail \n", 311 | " body = \"Your rClone Task has Completed! Visit link to view : https://colab.research.google.com/github/SKGHD/Handy/blob/master/HandBrakeCLI_Colab.ipynb\"\n", 312 | "\n", 313 | " msg.attach(MIMEText(body, 'plain'))\n", 314 | " filename = \"rClone_log.txt\"\n", 315 | " attachment = open(\"/content/rClone_log.txt\", \"rb\")\n", 316 | " p = MIMEBase('application', 'octet-stream') \n", 317 | " p.set_payload((attachment).read()) \n", 318 | " # encode into base64 \n", 319 | " encoders.encode_base64(p) \n", 320 | " \n", 321 | " p.add_header('Content-Disposition', \"attachment; filename= %s\" % filename) \n", 322 | " msg.attach(p) \n", 323 | " s = smtplib.SMTP('smtp.gmail.com', 587) \n", 324 | " s.starttls() \n", 325 | " s.login(fromaddr, password) \n", 326 | " text = msg.as_string() \n", 327 | " s.sendmail(fromaddr, toaddr, text)\n", 328 | " print(\"Email Alert Sent with log!\") \n", 329 | " s.quit() \n", 330 | " elif (Email_notification == False and logs == False):\n", 331 | " print(\"You will not receive any notification!!!.\")\n", 332 | " runrClone()\n", 333 | "checkEmail()" 334 | ], 335 | "execution_count": null, 336 | "outputs": [] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "a9Zjw2QUTP1A" 342 | }, 343 | "source": [ 344 | "#
***HandBrake***
\n", 345 | "#
" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "metadata": { 351 | "id": "Jdu112hxo6_M", 352 | "cellView": "form" 353 | }, 354 | "source": [ 355 | "#@title
HandBrake Configuration
\n", 356 | "#@markdown > Select Mode ( Batch conversion/ Single File)\n", 357 | "MODE = \"SINGLE\" #@param [\"SINGLE\", \"BATCH\"]\n", 358 | "\n", 359 | "\n", 360 | "#@markdown ---\n", 361 | "SOURCE = \"\" #@param {type:\"string\"}\n", 362 | "DESTINATION = \"\" #@param {type:\"string\"}\n", 363 | "FORMAT = \"mp4\" #@param [\"mp4\", \"mkv\"]\n", 364 | "RESOLUTION = \"480p\" #@param [\"360p\", \"480p\",\"540p\", \"720p\", \"1080p\"]\n", 365 | "Encoder = \"x264\" #@param [\"x264\", \"x265\"]\n", 366 | "Encoder_Preset = \"ultrafast\" #@param [\"ultrafast\", \"faster\", \"fast\", \"medium\", \"slow\", \"slower\"]\n", 367 | "#@markdown Choose Constant Quality Rate [Lower = Higher Quality/\n", 368 | "#@markdown Larger File Size]\n", 369 | "CQ = 30 #@param {type:\"slider\", min:10, max:30, step:1}\n", 370 | "BURN_SUBTITLES = False #@param {type:\"boolean\"}\n", 371 | "Additional_Flags = \"\" #@param {type:\"string\"}\n", 372 | "#@markdown ---\n", 373 | "Email_Alert = False #@param {type:\"boolean\"}\n", 374 | "MESSAGE = \"HandBrakeCLI_Colab has finished working\" #@param [\"HandBrake has finished working\"] {allow-input: true}\n", 375 | "SENDER_ID =\"\" #@param {type:\"string\"}\n", 376 | "SENDER_PASS=\"\" #@param {type:\"string\"}\n", 377 | "RECEIVER_ID=\"\" #@param {type:\"string\"}\n", 378 | "#@markdown >##### Using an app specific password is recommended: https://myaccount.google.com/apppasswords\n", 379 | "\n", 380 | "########################################################\n", 381 | "import smtplib\n", 382 | "import os\n", 383 | "\n", 384 | "\n", 385 | "formats = ('.mkv','.mp4','.ts','.avi','.mov','.wmv')\n", 386 | "\n", 387 | "######## Renames the file ########\n", 388 | "def fileName(fPath):\n", 389 | " tName = fPath.split('/')[-1] \n", 390 | " if tName.endswith('ts'):\n", 391 | " tName = '[HANDY] ' + tName[:-3] + f' [{RESOLUTION}] [{Encoder}].{FORMAT}' \n", 392 | " else:\n", 393 | " tName = '[HANDY] ' + tName[:-4] + f' [{RESOLUTION}] [{Encoder}].{FORMAT}' \n", 394 | " return tName\n", 395 | "\n", 396 | "def set_resolution():\n", 397 | " global w,h,flags\n", 398 | " if RESOLUTION == \"360p\":\n", 399 | " w, h = \"480\" , \"360\"\n", 400 | " elif RESOLUTION == \"480p\":\n", 401 | " w, h = \"854\" , \"480\"\n", 402 | " elif RESOLUTION == \"540p\":\n", 403 | " w, h = \"960\" , \"540\"\n", 404 | " elif RESOLUTION == \"720p\":\n", 405 | " w, h = \"1280\" , \"720\"\n", 406 | " elif RESOLUTION == \"1080p\":\n", 407 | " w, h = \"1920\" , \"1080\"\n", 408 | "\n", 409 | "def addFlags():\n", 410 | " global flags\n", 411 | " flags = f\" --encoder {Encoder} --all-audio -s '0,1,2,3' --cfr --optimize --quality={CQ} --width={w} --height={h} --format={FORMAT} --encoder-preset={Encoder_Preset} \"\n", 412 | " if BURN_SUBTITLES:\n", 413 | " flags += \"-s '1' --subtitle-burned '1' \"\n", 414 | " if Additional_Flags != \"\":\n", 415 | " flags += str(Additional_Flags)\n", 416 | "\n", 417 | "set_resolution()\n", 418 | "addFlags()\n", 419 | "\n", 420 | "##### HandBrake and Rclone #####\n", 421 | "def runner(path):\n", 422 | " f_name = fileName(path)\n", 423 | " hTemp=f\"/content/temp/HandbrakeTemp/{f_name}\"\n", 424 | " !HandBrakeCLI -i \"$path\" -o \"$hTemp\" $flags\n", 425 | " \n", 426 | " \n", 427 | " if os.path.isfile(hTemp):\n", 428 | " print(f\"\\n\\n********** Successfully converted {f_name}\\n Now saving to Destination.....\")\n", 429 | " if os.path.exists('/usr/bin/rclone'):\n", 430 | " !rclone move \"$hTemp\" --user-agent \"Mozilla\" \"$DESTINATION\" --transfers 20 --checkers 20 --stats-one-line --stats=5s -v --tpslimit 95 --tpslimit-burst 40\n", 431 | " else:\n", 432 | " dest = DESTINATION+'/'+f_name\n", 433 | " !mv \"$hTemp\" \"$dest\"\n", 434 | " if os.path.isfile(DESTINATION+ '/' +f_name): \n", 435 | " print(f\"\\n\\n********** Successfully saved {f_name} to Destination\")\n", 436 | "\n", 437 | "########## Check Mode ########\n", 438 | "if MODE==\"BATCH\":\n", 439 | " os.makedirs(DESTINATION, exist_ok=True)\n", 440 | " if SOURCE.endswith('/'):\n", 441 | " pass\n", 442 | " else: SOURCE +='/'\n", 443 | " filesList = os.listdir(SOURCE+'.')\n", 444 | " if os.path.isfile(SOURCE+'processed_db.txt'):\n", 445 | " pass\n", 446 | " else:\n", 447 | " with open((SOURCE+'processed_db.txt'), 'w') as fb:\n", 448 | " fb.write(\"Do not delete this file until all files have been processed!\\n\")\n", 449 | " fb.close()\n", 450 | " with open((SOURCE+'processed_db.txt'), \"r+\") as filehandle:\n", 451 | " processedList = [x.rstrip() for x in filehandle.readlines()]\n", 452 | "\n", 453 | " print('<<<<<<<<<<<<<<<<<< Starting Conversion in Batch mode. >>>>>>>>>>>>>>>>>>')\n", 454 | "\n", 455 | " for currentFile in filesList:\n", 456 | " if currentFile.endswith(formats):\n", 457 | " if currentFile not in processedList:\n", 458 | " currentPath = SOURCE + currentFile \n", 459 | " print(f'\\n\\n**************** Current File to process: {currentFile}')\n", 460 | " runner(currentPath)\n", 461 | " filehandle.write(currentFile+'\\n')\n", 462 | " filehandle.close()\n", 463 | " \n", 464 | "\n", 465 | "else:\n", 466 | " if SOURCE.endswith(formats): \n", 467 | " runner(SOURCE)\n", 468 | " else: print(\"Are you sure you have selected the correct file??\")\n", 469 | "\n", 470 | "########### Sending Notification ###############\n", 471 | "if Email_Alert == True: \n", 472 | " from email.mime.multipart import MIMEMultipart \n", 473 | " from email.mime.text import MIMEText \n", 474 | " msg = MIMEMultipart()\n", 475 | " msg['From'] = SENDER_ID\n", 476 | " msg['To'] = RECEIVER_ID\n", 477 | " msg['Subject'] = \"HandBrakeCLI_Colab has finished executing!\" \n", 478 | " \n", 479 | " msg.attach(MIMEText(MESSAGE))\n", 480 | " s = smtplib.SMTP('smtp.gmail.com', 587) \n", 481 | " s.starttls() \n", 482 | " s.login(SENDER_ID, SENDER_PASS)\n", 483 | " s.sendmail(SENDER_ID, RECEIVER_ID, msg.as_string())\n", 484 | " print(\"Email Alert Sent!\") \n", 485 | " s.quit()\n" 486 | ], 487 | "execution_count": null, 488 | "outputs": [] 489 | }, 490 | { 491 | "cell_type": "markdown", 492 | "metadata": { 493 | "id": "YceU6ECgzFxG" 494 | }, 495 | "source": [ 496 | "# Audio Video Tools" 497 | ] 498 | }, 499 | { 500 | "cell_type": "code", 501 | "metadata": { 502 | "id": "CCn6s3RvzO9o" 503 | }, 504 | "source": [ 505 | "#@title Extract 🎼Audio from Video 🎞 { display-mode: \"form\" }\n", 506 | "import os\n", 507 | "Input_File = \"Paste/Path/to/video_file.mp4\" #@param {type:\"string\"}\n", 508 | "Output_File_Name = \"extracted_audio.mp3\" #@param {type:\"string\"}\n", 509 | "fPath = os.path.dirname(Input_File) +'/'+ Output_File_Name\n", 510 | "\n", 511 | "\n", 512 | "!ffmpeg -i Input_File -vn -acodec copy fPath\n", 513 | "#@markdown >##### Save file name with extension like .mp3, .aac " 514 | ], 515 | "execution_count": null, 516 | "outputs": [] 517 | }, 518 | { 519 | "cell_type": "code", 520 | "metadata": { 521 | "id": "SuIsOEllzgOH" 522 | }, 523 | "source": [ 524 | "#@title Remove Audio 🎼 from Video 🎞 { display-mode: \"form\" }\n", 525 | "\n", 526 | "import os\n", 527 | "Input_File = \"Paste/Path/to/video_file.mp4\" #@param {type:\"string\"}\n", 528 | "Output_File_Name = \"video_file_without_audio.mp4\" #@param {type:\"string\"}\n", 529 | "fPath = os.path.dirname(Input_File) +'/'+ Output_File_Name\n", 530 | "\n", 531 | "!ffmpeg -i Input_File -codec copy -an fPath\n", 532 | "\n" 533 | ], 534 | "execution_count": null, 535 | "outputs": [] 536 | }, 537 | { 538 | "cell_type": "code", 539 | "metadata": { 540 | "cellView": "form", 541 | "id": "9NxOZ-kr-xBp" 542 | }, 543 | "source": [ 544 | "#@title Extract Images 🖼 from a Video 🎞🎞\n", 545 | "import os\n", 546 | "Input_File = \"Paste/Path/to/video_file.mp4\" #@param {type:\"string\"}\n", 547 | "dir_path = os.path.dirname(Input_File)\n", 548 | "os.makedirs(os.path.join(dir_path,'Extracted_Images'))\n", 549 | "!ffmpeg -i Input_File dir_path/Extracted_Images/image%d.jpg" 550 | ], 551 | "execution_count": null, 552 | "outputs": [] 553 | }, 554 | { 555 | "cell_type": "markdown", 556 | "metadata": { 557 | "id": "SyR9RfbxIloN" 558 | }, 559 | "source": [ 560 | "# Testing Area(Unfinished)" 561 | ] 562 | }, 563 | { 564 | "cell_type": "code", 565 | "metadata": { 566 | "cellView": "form", 567 | "id": "w2rRu1U0rXdF" 568 | }, 569 | "source": [ 570 | " \n", 571 | "#@markdown
\"rclone
\n", 572 | "#@markdown
Unlimited Transfer
\n", 573 | "#@markdown >##### You'll need to manually enter remote names but this doesn't rely on colab's storage so you can transfer as much as you need without limits.\n", 574 | "#@markdown ---\n", 575 | "source = \"\" #@param {type:\"string\"}\n", 576 | "source_remote = \"\" #@param {type:\"string\"}\n", 577 | "destination = \"\" #@param {type:\"string\"}\n", 578 | "destination_remote = \"\" #@param {type:\"string\"}\n", 579 | "mode = \"copy\" #@param [\"copy\", \"check\", \"sync\"]\n", 580 | "dry_run = False #@param {type:\"boolean\"}\n", 581 | "Extra_args = \"\" #@param {type:\"string\"}\n", 582 | "#@markdown ---\n", 583 | "Email_notification = True #@param {type:\"boolean\"}\n", 584 | "logs = False #@param {type:\"boolean\"}\n", 585 | "emailID = \"\" #@param {type:\"string\"}\n", 586 | "password = \"\" #@param {type:\"string\"}\n", 587 | "Receiver_ID = \"\" #@param {type:\"string\"}\n", 588 | "#@markdown ---\n", 589 | "import smtplib \n", 590 | "########################################\n", 591 | "#args = \"--transfers 20 --checkers 20 --stats-one-line --stats=5s -v --tpslimit 95 --tpslimit-burst 40 \"\n", 592 | "args = \" --stats-one-line --stats=5s -v \"\n", 593 | "if mode == \"check\":\n", 594 | " args += \"--one-way \"\n", 595 | "if dry_run == True:\n", 596 | " args +=\" --dry-run \"\n", 597 | "if logs == True:\n", 598 | " args += \" --log-file rClone_log.txt \"\n", 599 | "if Extra_args != \"\":\n", 600 | " args +=Extra_args\n", 601 | "######################################\n", 602 | "def runrClone():\n", 603 | " !rclone --user-agent \"Mozilla\" \"$mode\" $source_remote:\"$source\" $destination_remote:\"$destination\" $args\n", 604 | " \n", 605 | "def checkEmail():\n", 606 | " if (Email_notification == True and logs == False):\n", 607 | " print(\"You will receive only a notification after task has finished.\")\n", 608 | " runrClone()\n", 609 | " #Send only notification\n", 610 | " \n", 611 | " s = smtplib.SMTP('smtp.gmail.com', 587) \n", 612 | " s.starttls() \n", 613 | " s.login(emailID , password)\n", 614 | " message = \"Your rClone task has Completed!\"\n", 615 | " s.sendmail(emailID, Receiver_ID, message)\n", 616 | " print(\"Email Alert Sent!\") \n", 617 | " s.quit()\n", 618 | " elif (Email_notification == True and logs == True):\n", 619 | " print(\"You will receive a notification with log attached after task has finished.\")\n", 620 | " runrClone()\n", 621 | " #Sending email notification with logs\n", 622 | " \n", 623 | " from email.mime.multipart import MIMEMultipart \n", 624 | " from email.mime.text import MIMEText \n", 625 | " from email.mime.base import MIMEBase \n", 626 | " from email import encoders \n", 627 | "\n", 628 | " fromaddr = emailID\n", 629 | " toaddr = Receiver_ID\n", 630 | " msg = MIMEMultipart() \n", 631 | " # storing the senders email address \n", 632 | " msg['From'] = fromaddr \n", 633 | " # storing the receivers email address \n", 634 | " msg['To'] = toaddr \n", 635 | " # storing the subject \n", 636 | " msg['Subject'] = \"Colab has Finished Running your Cell\"\n", 637 | " # string to store the body of the mail \n", 638 | " body = \"Your rClone Task has Completed! Visit link to view : https://colab.research.google.com/github/SKGHD/Handy/blob/master/HandyCLI.ipynb\"\n", 639 | "\n", 640 | " msg.attach(MIMEText(body, 'plain'))\n", 641 | " filename = \"rClone_log.txt\"\n", 642 | " attachment = open(\"/content/rClone_log.txt\", \"rb\")\n", 643 | " p = MIMEBase('application', 'octet-stream') \n", 644 | " p.set_payload((attachment).read()) \n", 645 | " # encode into base64 \n", 646 | " encoders.encode_base64(p) \n", 647 | " \n", 648 | " p.add_header('Content-Disposition', \"attachment; filename= %s\" % filename) \n", 649 | " msg.attach(p) \n", 650 | " s = smtplib.SMTP('smtp.gmail.com', 587) \n", 651 | " s.starttls() \n", 652 | " s.login(fromaddr, password) \n", 653 | " text = msg.as_string() \n", 654 | " s.sendmail(fromaddr, toaddr, text)\n", 655 | " print(\"Email Alert Sent with log!\") \n", 656 | " s.quit() \n", 657 | " elif (Email_notification == False and logs == False):\n", 658 | " print(\"You will not receive any notification!!!.\")\n", 659 | " runrClone()\n", 660 | "checkEmail()" 661 | ], 662 | "execution_count": null, 663 | "outputs": [] 664 | } 665 | ] 666 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HandBrakeCLI-ColabNotebook v1.3 2 | 3 | Consider giving this repo a star ⭐ if it helped you. 4 | 5 |
Contact using TwitterGithub
6 | 7 |

Features:

8 |
  • Mount/Unmount your Cloud drive with rClone.
  • 9 |
  • Transfer files between your cloud drives with the speed of google's fast servers.
  • 10 |
  • Convert videos online with the help of HandBrake.
  • 11 |
  • Batch Convert directories.
  • 12 |
  • Resume support for Batch conversion jobs. Pick up right after the last successful conversion in Batch Job when your colab notebook restarts or disconnects.
  • 13 |
  • Get email notification when your task(s) have finished.
  • 14 |
  • Extract audio from video clips!
  • 15 |
  • Remove audio from video clips!
  • 16 |
  • Extract images from video clips!
  • 17 | 18 | 19 | # Usage 20 | 21 | Click on the "Open in Colab" button. 22 | [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/SKGHD/Handy/blob/master/HandBrakeCLI_Colab.ipynb) 23 | 24 | # Notes 25 | 26 |
  • To use email notifications only gmail id can be used and use an app specfic password Google account settings in order for the feature to work.
  • 27 |
  • Only you and those who can see your screen physically can see your passwords.
  • 28 |
  • Your passwords are stored in a local variable in your Jupyter Notebook and not stored anywhere less. It gets automatically destroyed when Google purges your notebook.
  • 29 |
  • Do not remove processed_db.txt from your current batch directory else it'll process same files again and again each time you restart the notebook!
  • 30 |
    31 |

    Read more about app specific passwords here: Google Account Help 32 | 33 | # FAQs 34 | 35 |

  • Q> What is rclone? How do I get rclone.conf file?
  • 36 |
  • A> Everything has been answer here in this forum. Please have a read :Rclone
  • 37 |
  • Q> How to add more flags to the script?
  • 38 |
  • A> Just add them to the Additional_Flags: ______ in below format.
  • 39 | Example:
    40 | `--bframes '8' rc-lookahead '40' no-rect` 41 |
    42 | Note: Numbers should be in single quotes. 43 | 44 |
  • Q> Where do I ask for help or feature requests?
  • 45 |
  • A> Open a new request or issue here in github. Please don't message me directly.
  • 46 | 47 | ### Handbrake CLI reference 48 | 49 |

    Read more about CLI commands here: Handbrake CLI Docs 50 |
    51 | 52 | ## Pull Requests are welcome. 53 | --------------------------------------------------------------------------------