mirror of
https://github.com/neosubhamoy/pytubepp.git
synced 2026-02-04 18:22:23 +05:30
Compare commits
8 Commits
v1.0.2-sta
...
v1.0.4-sta
14
README.md
14
README.md
@@ -3,7 +3,7 @@
|
|||||||
### A Simple CLI Tool to Download Your Favourite YouTube Videos Effortlessly!
|
### A Simple CLI Tool to Download Your Favourite YouTube Videos Effortlessly!
|
||||||
|
|
||||||
[](https://github.com/neosubhamoy/pytubepp/)
|
[](https://github.com/neosubhamoy/pytubepp/)
|
||||||
[](https://github.com/neosubhamoy/pytubepp/)
|
[](https://github.com/neosubhamoy/pytubepp/)
|
||||||
[](https://www.python.org/downloads/)
|
[](https://www.python.org/downloads/)
|
||||||
[](https://github.com/neosubhamoy/pytubepp/)
|
[](https://github.com/neosubhamoy/pytubepp/)
|
||||||
[](https://github.com/neosubhamoy/pytubepp/)
|
[](https://github.com/neosubhamoy/pytubepp/)
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
### **🏷️ Features**
|
### **🏷️ Features**
|
||||||
* Auto Post-Process & Merge YouTube DASH Streams
|
* Auto Post-Process & Merge YouTube DASH Streams
|
||||||
|
* Supports upto 8K 60fps HDR Stream Download
|
||||||
* Supports MP3 Download (with Embeded Thumbnail and Tags)
|
* Supports MP3 Download (with Embeded Thumbnail and Tags)
|
||||||
* Smart Stream Selection
|
* Smart Stream Selection
|
||||||
* Highly Configurable and Many More 😉
|
* Highly Configurable and Many More 😉
|
||||||
@@ -37,7 +38,7 @@ pip install pytubepp
|
|||||||
**>> Install FFmpeg (If you haven't already!)**
|
**>> Install FFmpeg (If you haven't already!)**
|
||||||
|
|
||||||
Linux (Ubuntu): `apt install ffmpeg`<br>
|
Linux (Ubuntu): `apt install ffmpeg`<br>
|
||||||
Windows (using Chocolatey): `choco install ffmpeg`<br>
|
Windows (10/11): `winget install ffmpeg`<br>
|
||||||
MacOS (using Homebrew): `brew install ffmpeg`<br>
|
MacOS (using Homebrew): `brew install ffmpeg`<br>
|
||||||
Android (using Termux): `pkg install ffmpeg`
|
Android (using Termux): `pkg install ffmpeg`
|
||||||
|
|
||||||
@@ -56,13 +57,18 @@ pytubepp "https://youtube.com/watch?v=2lAe1cqCOXo" -s 480p
|
|||||||
```terminal
|
```terminal
|
||||||
pytubepp "https://youtube.com/watch?v=2lAe1cqCOXo" -s mp3
|
pytubepp "https://youtube.com/watch?v=2lAe1cqCOXo" -s mp3
|
||||||
```
|
```
|
||||||
|
* To fetch the video information the command will be:
|
||||||
|
```terminal
|
||||||
|
pytubepp "https://youtube.com/watch?v=2lAe1cqCOXo" -i
|
||||||
|
```
|
||||||
|
* To cancel/stop an ongoing download press `CTRL` + `C` on keyboard (it is recommended to run the `-ct` flag once after canceling an ongoing download).
|
||||||
* List of all available flags are given below:
|
* List of all available flags are given below:
|
||||||
|
|
||||||
| Flag | Usage | Requires Parameter | Requires URL | Parameters | Default |
|
| Flag | Usage | Requires Parameter | Requires URL | Parameters | Default |
|
||||||
| :--- | :--- | :--- | :--- | :--- | :--- |
|
| :--- | :--- | :--- | :--- | :--- | :--- |
|
||||||
| -s | Choose preferred download stream | YES | YES | `144` `144p` `240` `240p` `360` `360p` `480` `480p` `720` `720p` `hd` `1080` `1080p` `fhd` `1440` `1440p` `2k` `2160` `2160p` `4k` `mp3` (Pass any one of them) | Your chosen Default Stream via `-ds` flag |
|
| -s | Choose preferred download stream | YES | YES | `144` `144p` `240` `240p` `360` `360p` `480` `480p` `720` `720p` `hd` `1080` `1080p` `fhd` `1440` `1440p` `2k` `2160` `2160p` `4k` `4320` `4320p` `8k` `mp3` (Pass any one of them) | Your chosen Default Stream via `-ds` flag |
|
||||||
| -i | Shows the video information like: Title, Author, Views, Available Download Streams | NO | YES | No parameters | No default |
|
| -i | Shows the video information like: Title, Author, Views, Available Download Streams | NO | YES | No parameters | No default |
|
||||||
| -ds | Set default download stream | YES | NO | `144p` `240p` `360p` `480p` `720p` `1080p` `1440p` `2160p` `mp3` `max` (Pass any one of them) | `max` |
|
| -ds | Set default download stream | YES | NO | `144p` `240p` `360p` `480p` `720p` `1080p` `1440p` `2160p` `4320p` `mp3` `max` (Pass any one of them) | `max` |
|
||||||
| -df | Set custom download folder path | YES | NO | Use the full path excluding the last trailing slash within double quotes eg(in Linux): `"/path/to/folder"` (Make sure the folder path you enterted is already created and accessable) | Within `Pytube Downloads` folder in your System's `Downloads` folder |
|
| -df | Set custom download folder path | YES | NO | Use the full path excluding the last trailing slash within double quotes eg(in Linux): `"/path/to/folder"` (Make sure the folder path you enterted is already created and accessable) | Within `Pytube Downloads` folder in your System's `Downloads` folder |
|
||||||
| -r | Reset to default configuration (Download Folder, Default Stream) | NO | NO | No parameters | No default |
|
| -r | Reset to default configuration (Download Folder, Default Stream) | NO | NO | No parameters | No default |
|
||||||
| -sc | Show all current user configurations | NO | NO | No parameters | No default |
|
| -sc | Show all current user configurations | NO | NO | No parameters | No default |
|
||||||
|
|||||||
229
pytubepp/main.py
229
pytubepp/main.py
@@ -2,12 +2,13 @@ from pytubefix import YouTube
|
|||||||
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB
|
from mutagen.id3 import ID3, APIC, TIT2, TPE1, TALB
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
import appdirs, ffmpy, requests, re, os, sys, random, shutil, platform, json, argparse, tempfile, pkg_resources
|
from importlib.metadata import version
|
||||||
|
import appdirs, ffmpy, requests, re, os, sys, random, shutil, platform, json, argparse, tempfile
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
try:
|
try:
|
||||||
return pkg_resources.get_distribution("pytubepp").version
|
return version('pytubepp')
|
||||||
except pkg_resources.DistributionNotFound:
|
except Exception as e:
|
||||||
return "Unknown"
|
return "Unknown"
|
||||||
|
|
||||||
def get_download_folder():
|
def get_download_folder():
|
||||||
@@ -137,10 +138,10 @@ def convert_to_mp3(title, thumbnail_url, random_filename, mp3_artist='Unknown',
|
|||||||
print('Done! 🎉')
|
print('Done! 🎉')
|
||||||
|
|
||||||
def download_progressive(stream, itag, title, resolution, file_extention, tempDIR=tempDIR, downloadDIR=downloadDIR):
|
def download_progressive(stream, itag, title, resolution, file_extention, tempDIR=tempDIR, downloadDIR=downloadDIR):
|
||||||
global vdo_filesize, progress_bar
|
global total_filesize, progress_bar
|
||||||
selected_vdo = stream.get_by_itag(itag)
|
selected_vdo = stream.get_by_itag(itag)
|
||||||
vdo_filesize = selected_vdo.filesize
|
total_filesize = selected_vdo.filesize
|
||||||
progress_bar = tqdm(total=vdo_filesize, unit='B', unit_scale=True, desc="Downloading")
|
progress_bar = tqdm(total=total_filesize, unit='B', unit_scale=True, desc="Downloading Video+Audio")
|
||||||
random_filename = str(random.randint(1000000000, 9999999999))
|
random_filename = str(random.randint(1000000000, 9999999999))
|
||||||
filename = random_filename + '_vdo.' + file_extention
|
filename = random_filename + '_vdo.' + file_extention
|
||||||
output_temp_file = os.path.join(tempDIR, filename)
|
output_temp_file = os.path.join(tempDIR, filename)
|
||||||
@@ -151,21 +152,23 @@ def download_progressive(stream, itag, title, resolution, file_extention, tempDI
|
|||||||
print('Done! 🎉')
|
print('Done! 🎉')
|
||||||
|
|
||||||
def download_nonprogressive(stream, itag_vdo, itag_ado, file_extention, output_path):
|
def download_nonprogressive(stream, itag_vdo, itag_ado, file_extention, output_path):
|
||||||
global vdo_filesize, progress_bar
|
global total_filesize, progress_bar
|
||||||
selected_vdo = stream.get_by_itag(itag_vdo)
|
selected_vdo = stream.get_by_itag(itag_vdo)
|
||||||
selected_ado = stream.get_by_itag(itag_ado)
|
selected_ado = stream.get_by_itag(itag_ado)
|
||||||
vdo_filesize = selected_vdo.filesize
|
|
||||||
progress_bar = tqdm(total=vdo_filesize, unit='B', unit_scale=True, desc="Downloading")
|
|
||||||
random_filename = str(random.randint(1000000000, 9999999999))
|
random_filename = str(random.randint(1000000000, 9999999999))
|
||||||
|
total_filesize = selected_vdo.filesize
|
||||||
|
progress_bar = tqdm(total=total_filesize, unit='B', unit_scale=True, desc="Downloading Video")
|
||||||
selected_vdo.download(output_path=output_path, filename=random_filename + '_vdo.' + file_extention)
|
selected_vdo.download(output_path=output_path, filename=random_filename + '_vdo.' + file_extention)
|
||||||
|
total_filesize = selected_ado.filesize
|
||||||
|
progress_bar = tqdm(total=total_filesize, unit='B', unit_scale=True, desc="Downloading Audio")
|
||||||
selected_ado.download(output_path=output_path, filename=random_filename + '_ado.' + file_extention)
|
selected_ado.download(output_path=output_path, filename=random_filename + '_ado.' + file_extention)
|
||||||
return random_filename
|
return random_filename
|
||||||
|
|
||||||
def download_audio(stream, itag, output_path):
|
def download_audio(stream, itag, output_path):
|
||||||
global vdo_filesize, progress_bar
|
global total_filesize, progress_bar
|
||||||
selected_ado = stream.get_by_itag(itag)
|
selected_ado = stream.get_by_itag(itag)
|
||||||
vdo_filesize = selected_ado.filesize
|
total_filesize = selected_ado.filesize
|
||||||
progress_bar = tqdm(total=vdo_filesize, unit='B', unit_scale=True, desc="Downloading")
|
progress_bar = tqdm(total=total_filesize, unit='B', unit_scale=True, desc="Downloading Audio")
|
||||||
random_filename = str(random.randint(1000000000, 9999999999))
|
random_filename = str(random.randint(1000000000, 9999999999))
|
||||||
selected_ado.download(output_path=output_path, filename=random_filename + '_ado.mp4')
|
selected_ado.download(output_path=output_path, filename=random_filename + '_ado.mp4')
|
||||||
return random_filename
|
return random_filename
|
||||||
@@ -188,7 +191,7 @@ def download_thumbnail(url, file_path):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
def progress(chunk, file_handle, bytes_remaining):
|
def progress(chunk, file_handle, bytes_remaining):
|
||||||
chunk_size = vdo_filesize - bytes_remaining
|
chunk_size = total_filesize - bytes_remaining
|
||||||
progress_bar.update(chunk_size - progress_bar.n)
|
progress_bar.update(chunk_size - progress_bar.n)
|
||||||
|
|
||||||
if bytes_remaining == 0:
|
if bytes_remaining == 0:
|
||||||
@@ -239,41 +242,45 @@ def set_global_video_info(link):
|
|||||||
views = str(video.views)
|
views = str(video.views)
|
||||||
stream = video.streams
|
stream = video.streams
|
||||||
stream_resolutions = {
|
stream_resolutions = {
|
||||||
|
'4320p': {
|
||||||
|
'allowed_streams': ['8k', '4320', '4320p'],
|
||||||
|
'message': ['4320p', '[8k, 4320, 4320p]']
|
||||||
|
},
|
||||||
'2160p': {
|
'2160p': {
|
||||||
'allowed_streams': ['4k', '2160', '2160p'],
|
'allowed_streams': ['4k', '2160', '2160p'],
|
||||||
'message': ['2160p', 'webm', 'vp90', 'opus', '[4k, 2160, 2160p]']
|
'message': ['2160p', '[4k, 2160, 2160p]']
|
||||||
},
|
},
|
||||||
'1440p': {
|
'1440p': {
|
||||||
'allowed_streams': ['2k', '1440', '1440p'],
|
'allowed_streams': ['2k', '1440', '1440p'],
|
||||||
'message': ['1440p', 'webm', 'vp90', 'opus', '[2k, 1440, 1440p]']
|
'message': ['1440p', '[2k, 1440, 1440p]']
|
||||||
},
|
},
|
||||||
'1080p': {
|
'1080p': {
|
||||||
'allowed_streams': ['fhd', '1080', '1080p'],
|
'allowed_streams': ['fhd', '1080', '1080p'],
|
||||||
'message': ['1080p', 'mp4', 'avc1', 'aac', '[fhd, 1080, 1080p]']
|
'message': ['1080p', '[fhd, 1080, 1080p]']
|
||||||
},
|
},
|
||||||
'720p': {
|
'720p': {
|
||||||
'allowed_streams': ['hd', '720', '720p'],
|
'allowed_streams': ['hd', '720', '720p'],
|
||||||
'message': ['720p', 'mp4', 'avc1', 'aac', '[hd, 720, 720p]']
|
'message': ['720p', '[hd, 720, 720p]']
|
||||||
},
|
},
|
||||||
'480p': {
|
'480p': {
|
||||||
'allowed_streams': ['480', '480p'],
|
'allowed_streams': ['480', '480p'],
|
||||||
'message': ['480p', 'mp4', 'avc1', 'aac', '[480, 480p]']
|
'message': ['480p', '[480, 480p]']
|
||||||
},
|
},
|
||||||
'360p': {
|
'360p': {
|
||||||
'allowed_streams': ['360', '360p'],
|
'allowed_streams': ['360', '360p'],
|
||||||
'message': ['360p', 'mp4', 'avc1', 'aac', '[360, 360p]']
|
'message': ['360p', '[360, 360p]']
|
||||||
},
|
},
|
||||||
'240p': {
|
'240p': {
|
||||||
'allowed_streams': ['240', '240p'],
|
'allowed_streams': ['240', '240p'],
|
||||||
'message': ['240p', 'mp4', 'avc1', 'aac', '[240, 240p]']
|
'message': ['240p', '[240, 240p]']
|
||||||
},
|
},
|
||||||
'144p': {
|
'144p': {
|
||||||
'allowed_streams': ['144', '144p'],
|
'allowed_streams': ['144', '144p'],
|
||||||
'message': ['144p', 'mp4', 'avc1', 'aac', '[144, 144p]']
|
'message': ['144p', '[144, 144p]']
|
||||||
},
|
},
|
||||||
'mp3': {
|
'mp3': {
|
||||||
'allowed_streams': ['mp3'],
|
'allowed_streams': ['mp3'],
|
||||||
'message': ['mp3', 'mp3', 'none', 'mp3', '[mp3]']
|
'message': ['mp3', '[mp3]']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for res in stream_resolutions.keys():
|
for res in stream_resolutions.keys():
|
||||||
@@ -297,10 +304,118 @@ def show_video_info(link):
|
|||||||
else:
|
else:
|
||||||
matching_stream = next((s for s in stream if s.resolution == res), None)
|
matching_stream = next((s for s in stream if s.resolution == res), None)
|
||||||
if matching_stream is not None:
|
if matching_stream is not None:
|
||||||
filesize = f"{matching_stream.filesize / (1024 * 1024):.2f} MB"
|
if res == '4320p':
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
if res == '2160p':
|
||||||
|
if stream.get_by_itag(701):
|
||||||
|
type = stream.get_by_itag(701).mime_type
|
||||||
|
filesize = f"{(stream.get_by_itag(701).filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{stream.get_by_itag(701).fps}fps"
|
||||||
|
vdo_codec = stream.get_by_itag(701).video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{stream.get_by_itag(701).bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
else:
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(251).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(251).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(251).abr
|
||||||
|
elif res == '1440p':
|
||||||
|
if stream.get_by_itag(700):
|
||||||
|
type = stream.get_by_itag(700).mime_type
|
||||||
|
filesize = f"{(stream.get_by_itag(700).filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{stream.get_by_itag(700).fps}fps"
|
||||||
|
vdo_codec = stream.get_by_itag(700).video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{stream.get_by_itag(700).bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
else:
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(251).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(251).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(251).abr
|
||||||
|
elif res == '1080p':
|
||||||
|
if stream.get_by_itag(699):
|
||||||
|
type = stream.get_by_itag(699).mime_type
|
||||||
|
filesize = f"{(stream.get_by_itag(699).filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{stream.get_by_itag(699).fps}fps"
|
||||||
|
vdo_codec = stream.get_by_itag(699).video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{stream.get_by_itag(699).bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
else:
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
elif res == '720p':
|
||||||
|
if stream.get_by_itag(698):
|
||||||
|
type = stream.get_by_itag(698).mime_type
|
||||||
|
filesize = f"{(stream.get_by_itag(698).filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{stream.get_by_itag(698).fps}fps"
|
||||||
|
vdo_codec = stream.get_by_itag(698).video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{stream.get_by_itag(698).bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
else:
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
elif res == '480p':
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(140).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(140).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(140).abr
|
||||||
|
elif res == '360p':
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{matching_stream.filesize / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = matching_stream.audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = matching_stream.abr
|
||||||
|
elif res in ['240p', '144p']:
|
||||||
|
type = matching_stream.mime_type
|
||||||
|
filesize = f"{(matching_stream.filesize + stream.get_by_itag(139).filesize) / (1024 * 1024):.2f} MB"
|
||||||
|
fps = f"{matching_stream.fps}fps"
|
||||||
|
vdo_codec = matching_stream.video_codec
|
||||||
|
ado_codec = stream.get_by_itag(139).audio_codec
|
||||||
|
vdo_bitrate = f"{matching_stream.bitrate / 1024:.0f}kbps"
|
||||||
|
ado_bitrate = stream.get_by_itag(139).abr
|
||||||
|
elif res == 'mp3':
|
||||||
|
type = "audio/mp3"
|
||||||
|
filesize = f"{matching_stream.filesize / (1024 * 1024):.2f} MB"
|
||||||
|
fps = "none"
|
||||||
|
vdo_codec = "none"
|
||||||
|
ado_codec = matching_stream.audio_codec
|
||||||
|
vdo_bitrate = "none"
|
||||||
|
ado_bitrate = matching_stream.abr
|
||||||
|
|
||||||
else:
|
else:
|
||||||
filesize = "N/A"
|
filesize = "N/A"
|
||||||
message = stream_resolutions[res]['message'] + [filesize]
|
message = stream_resolutions[res]['message'] + [type] + [filesize] + [fps] + [vdo_codec] + [ado_codec] + [vdo_bitrate] + [ado_bitrate]
|
||||||
table.append(message)
|
table.append(message)
|
||||||
|
|
||||||
if not found:
|
if not found:
|
||||||
@@ -308,7 +423,7 @@ def show_video_info(link):
|
|||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
print(f'\nTitle: {video.title}\nAuthor: {author}\nViews: {views}\n')
|
print(f'\nTitle: {video.title}\nAuthor: {author}\nViews: {views}\n')
|
||||||
print(tabulate(table, headers=['Streams', 'Format', 'Video Codec', 'Audio Codec', 'Aliases', 'Size']))
|
print(tabulate(table, headers=['Stream', 'Alias (for -s flag)', 'Format', 'Size', 'FrameRate', 'V-Codec', 'A-Codec', 'V-BitRate', 'A-BitRate']))
|
||||||
print('\n')
|
print('\n')
|
||||||
else:
|
else:
|
||||||
print('\nInvalid video link! Please enter a valid video url...!!')
|
print('\nInvalid video link! Please enter a valid video url...!!')
|
||||||
@@ -328,23 +443,25 @@ def get_allowed_streams(link):
|
|||||||
|
|
||||||
def print_short_info(chosen_stream):
|
def print_short_info(chosen_stream):
|
||||||
if chosen_stream in ['720', '720p', 'hd']:
|
if chosen_stream in ['720', '720p', 'hd']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 720p (HD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 720p (HD)\n')
|
||||||
elif chosen_stream in ['360', '360p']:
|
elif chosen_stream in ['360', '360p']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 360p (SD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 360p (SD)\n')
|
||||||
elif chosen_stream in ['1080', '1080p', 'fhd']:
|
elif chosen_stream in ['1080', '1080p', 'fhd']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 1080p (FHD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 1080p (FHD)\n')
|
||||||
elif chosen_stream in ['480', '480p']:
|
elif chosen_stream in ['480', '480p']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 480p (SD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 480p (SD)\n')
|
||||||
elif chosen_stream in ['240', '240p']:
|
elif chosen_stream in ['240', '240p']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 240p (LD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 240p (LD)\n')
|
||||||
elif chosen_stream in ['144', '144p']:
|
elif chosen_stream in ['144', '144p']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 144p (LD) [mp4 - avc1 - aac]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 144p (LD)\n')
|
||||||
|
elif chosen_stream in ['4320', '4320p', '8k']:
|
||||||
|
print(f'\nVideo: {title}\nSelected Stream: 4320p (8K)\n')
|
||||||
elif chosen_stream in ['2160', '2160p', '4k']:
|
elif chosen_stream in ['2160', '2160p', '4k']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 2160p (4K) [webm - vp90 - opus]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 2160p (4K)\n')
|
||||||
elif chosen_stream in ['1440', '1440p', '2k']:
|
elif chosen_stream in ['1440', '1440p', '2k']:
|
||||||
print(f'\nVideo: {title}\nSelected Stream: 1440p (2K) [webm - vp90 - opus]\n')
|
print(f'\nVideo: {title}\nSelected Stream: 1440p (2K)\n')
|
||||||
elif chosen_stream == 'mp3':
|
elif chosen_stream == 'mp3':
|
||||||
print(f'\nVideo: {title}\nSelected Stream: mp3 (Audio) [mp3 - dynamic - 44.1khz]\n')
|
print(f'\nVideo: {title}\nSelected Stream: mp3 (Audio)\n')
|
||||||
|
|
||||||
def download_stream(link, chosen_stream):
|
def download_stream(link, chosen_stream):
|
||||||
if set_global_video_info(link):
|
if set_global_video_info(link):
|
||||||
@@ -355,25 +472,51 @@ def download_stream(link, chosen_stream):
|
|||||||
download_progressive(stream, 18, title, '360p', 'mp4')
|
download_progressive(stream, 18, title, '360p', 'mp4')
|
||||||
|
|
||||||
elif chosen_stream in ['1080', '1080p', 'fhd']:
|
elif chosen_stream in ['1080', '1080p', 'fhd']:
|
||||||
merge_audio_video(title, '1080p', 'mp4', download_nonprogressive(stream, 137, 140, 'mp4', tempDIR))
|
if stream.get_by_itag(699):
|
||||||
|
merge_audio_video(title, '1080p', 'mp4', download_nonprogressive(stream, 699, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(299):
|
||||||
|
merge_audio_video(title, '1080p', 'mp4', download_nonprogressive(stream, 299, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(137):
|
||||||
|
merge_audio_video(title, '1080p', 'mp4', download_nonprogressive(stream, 137, 140, 'mp4', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['720', '720p', 'hd']:
|
elif chosen_stream in ['720', '720p', 'hd']:
|
||||||
merge_audio_video(title, '720p', 'mp4', download_nonprogressive(stream, 136, 140, 'mp4', tempDIR))
|
if stream.get_by_itag(698):
|
||||||
|
merge_audio_video(title, '720p', 'mp4', download_nonprogressive(stream, 698, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(298):
|
||||||
|
merge_audio_video(title, '720p', 'mp4', download_nonprogressive(stream, 298, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(136):
|
||||||
|
merge_audio_video(title, '720p', 'mp4', download_nonprogressive(stream, 136, 140, 'mp4', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['480', '480p']:
|
elif chosen_stream in ['480', '480p']:
|
||||||
merge_audio_video(title, '480p', 'mp4', download_nonprogressive(stream, 135, 140, 'mp4', tempDIR))
|
merge_audio_video(title, '480p', 'mp4', download_nonprogressive(stream, 135, 140, 'mp4', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['240', '240p']:
|
elif chosen_stream in ['240', '240p']:
|
||||||
merge_audio_video(title, '240p', 'mp4', download_nonprogressive(stream, 133, 140, 'mp4', tempDIR))
|
merge_audio_video(title, '240p', 'mp4', download_nonprogressive(stream, 133, 139, 'mp4', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['144', '144p']:
|
elif chosen_stream in ['144', '144p']:
|
||||||
merge_audio_video(title, '144p', 'mp4', download_nonprogressive(stream, 160, 140, 'mp4', tempDIR))
|
merge_audio_video(title, '144p', 'mp4', download_nonprogressive(stream, 160, 139, 'mp4', tempDIR))
|
||||||
|
|
||||||
|
elif chosen_stream in ['4320', '4320p', '8k']:
|
||||||
|
if stream.get_by_itag(702):
|
||||||
|
merge_audio_video(title, '8k', 'mp4', download_nonprogressive(stream, 702, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(571):
|
||||||
|
merge_audio_video(title, '8k', 'mp4', download_nonprogressive(stream, 571, 140, 'mp4', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['2160', '2160p', '4k']:
|
elif chosen_stream in ['2160', '2160p', '4k']:
|
||||||
merge_audio_video(title, '4k', 'webm', download_nonprogressive(stream, 313, 251, 'webm', tempDIR))
|
if stream.get_by_itag(701):
|
||||||
|
merge_audio_video(title, '4k', 'mp4', download_nonprogressive(stream, 701, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(315):
|
||||||
|
merge_audio_video(title, '4k', 'webm', download_nonprogressive(stream, 315, 251, 'webm', tempDIR))
|
||||||
|
elif stream.get_by_itag(313):
|
||||||
|
merge_audio_video(title, '4k', 'webm', download_nonprogressive(stream, 313, 251, 'webm', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream in ['1440', '1440p', '2k']:
|
elif chosen_stream in ['1440', '1440p', '2k']:
|
||||||
merge_audio_video(title, '2k', 'webm', download_nonprogressive(stream, 271, 251, 'webm', tempDIR))
|
if stream.get_by_itag(700):
|
||||||
|
merge_audio_video(title, '2k', 'mp4', download_nonprogressive(stream, 700, 140, 'mp4', tempDIR))
|
||||||
|
elif stream.get_by_itag(308):
|
||||||
|
merge_audio_video(title, '2k', 'webm', download_nonprogressive(stream, 308, 251, 'webm', tempDIR))
|
||||||
|
elif stream.get_by_itag(271):
|
||||||
|
merge_audio_video(title, '2k', 'webm', download_nonprogressive(stream, 271, 251, 'webm', tempDIR))
|
||||||
|
|
||||||
elif chosen_stream == 'mp3':
|
elif chosen_stream == 'mp3':
|
||||||
convert_to_mp3(title, thumbnail, download_audio(stream, 140, tempDIR), author, video.title, author)
|
convert_to_mp3(title, thumbnail, download_audio(stream, 140, tempDIR), author, video.title, author)
|
||||||
@@ -387,8 +530,8 @@ def main():
|
|||||||
parser = argparse.ArgumentParser(description=f'pytubePP (Pytube Post Processor) v{version} - A Simple CLI Tool to Download Your Favorite YouTube Videos Effortlessly!')
|
parser = argparse.ArgumentParser(description=f'pytubePP (Pytube Post Processor) v{version} - A Simple CLI Tool to Download Your Favorite YouTube Videos Effortlessly!')
|
||||||
parser.add_argument('url', nargs='?', default=None, help='url of the youtube video')
|
parser.add_argument('url', nargs='?', default=None, help='url of the youtube video')
|
||||||
parser.add_argument('-df', '--download-folder', default=argparse.SUPPRESS, help='set custom download folder path (default: ~/Downloads/Pytube Downloads) [arg eg: "/path/to/folder"]')
|
parser.add_argument('-df', '--download-folder', default=argparse.SUPPRESS, help='set custom download folder path (default: ~/Downloads/Pytube Downloads) [arg eg: "/path/to/folder"]')
|
||||||
parser.add_argument('-ds', '--default-stream', default=argparse.SUPPRESS, help='set default download stream (default: max) [available arguments: 144p, 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p, mp3, max]')
|
parser.add_argument('-ds', '--default-stream', default=argparse.SUPPRESS, help='set default download stream (default: max) [available arguments: 144p, 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p, 4320p, mp3, max]')
|
||||||
parser.add_argument('-s', '--stream', default=argparse.SUPPRESS, help='choose download stream for the current video (default: your chosen --default-stream) [available arguments: 144p, 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p, 144, 240, 360, 480, 720, 1080, 1440, 2160, mp3, hd, fhd, 2k, 4k]')
|
parser.add_argument('-s', '--stream', default=argparse.SUPPRESS, help='choose download stream for the current video (default: your chosen --default-stream) [available arguments: 144p, 240p, 360p, 480p, 720p, 1080p, 1440p, 2160p, 4320p, 144, 240, 360, 480, 720, 1080, 1440, 2160, 4320, mp3, hd, fhd, 2k, 4k, 8k]')
|
||||||
parser.add_argument('-i', '--show-info', action='store_true', help='show video info (title, author, views and available_streams)')
|
parser.add_argument('-i', '--show-info', action='store_true', help='show video info (title, author, views and available_streams)')
|
||||||
parser.add_argument('-sc', '--show-config', action='store_true', help='show all current user config settings')
|
parser.add_argument('-sc', '--show-config', action='store_true', help='show all current user config settings')
|
||||||
parser.add_argument('-r', '--reset-default', action='store_true', help='reset to default settings (download_folder and default_stream)')
|
parser.add_argument('-r', '--reset-default', action='store_true', help='reset to default settings (download_folder and default_stream)')
|
||||||
@@ -460,7 +603,7 @@ def main():
|
|||||||
|
|
||||||
if 'default_stream' in args:
|
if 'default_stream' in args:
|
||||||
if args.default_stream != defaultStream:
|
if args.default_stream != defaultStream:
|
||||||
if args.default_stream in ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p', 'mp3', 'max']:
|
if args.default_stream in ['144p', '240p', '360p', '480p', '720p', '1080p', '1440p', '2160p', '4320p', 'mp3', 'max']:
|
||||||
update_config('defaultStream', args.default_stream)
|
update_config('defaultStream', args.default_stream)
|
||||||
print(f'\nDefault stream updated to: {args.default_stream}')
|
print(f'\nDefault stream updated to: {args.default_stream}')
|
||||||
else:
|
else:
|
||||||
|
|||||||
3
setup.py
3
setup.py
@@ -6,7 +6,7 @@ with open('README.md', 'r', encoding='utf8') as file:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='pytubepp',
|
name='pytubepp',
|
||||||
version='1.0.2',
|
version='1.0.4',
|
||||||
description='A Simple CLI Tool to Download Your Favorite YouTube Videos Effortlessly!',
|
description='A Simple CLI Tool to Download Your Favorite YouTube Videos Effortlessly!',
|
||||||
long_description=readme,
|
long_description=readme,
|
||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
@@ -42,6 +42,7 @@ setup(
|
|||||||
"Programming Language :: Python :: 3.9",
|
"Programming Language :: Python :: 3.9",
|
||||||
"Programming Language :: Python :: 3.10",
|
"Programming Language :: Python :: 3.10",
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Topic :: Internet",
|
"Topic :: Internet",
|
||||||
"Topic :: Multimedia :: Video",
|
"Topic :: Multimedia :: Video",
|
||||||
|
|||||||
Reference in New Issue
Block a user