mirror of
https://github.com/neosubhamoy/pytubepp.git
synced 2025-12-19 22:53:05 +05:30
(feat): added post installation script -pi and improved docs
This commit is contained in:
40
README.md
40
README.md
@@ -13,6 +13,12 @@
|
||||
|
||||
> **🥰 Liked this project? Please consider giving it a Star (🌟) on github to show us your appreciation and help the algorythm recommend this project to even more awesome people like you!**
|
||||
|
||||
### **💻 Supported Platforms**
|
||||
- Windows (10 / 11)
|
||||
- Linux (Debian, Fedora, Arch)
|
||||
- MacOS
|
||||
- Android (Termux)
|
||||
|
||||
### **🏷️ Features**
|
||||
* Auto Post-Process & Merge YouTube DASH Streams
|
||||
* Supports upto 8K 60fps HDR Stream Download
|
||||
@@ -44,6 +50,9 @@
|
||||
- Windows (10/11): `winget install Python.Python.3.13`<br>
|
||||
- MacOS (using Homebrew): `brew install python`<br>
|
||||
- Android (using Termux): `pkg install python`
|
||||
|
||||
> You can skip step 2, 3 and auto install them later using the command `pytubepp --postinstall` post installation (works in: Windows, Linux - debian fedora arch, MacOS)
|
||||
|
||||
2. Install FFmpeg
|
||||
- Linux (Debian): `sudo apt install ffmpeg`<br>
|
||||
- Linux (Fedora) ([enable](https://docs.fedoraproject.org/en-US/quick-docs/rpmfusion-setup/#_enabling_the_rpm_fusion_repositories_using_command_line_utilities) rpmfusion free+nonfree repos before installing): `sudo dnf install ffmpeg`<br>
|
||||
@@ -68,7 +77,7 @@
|
||||
pip install pytubepp
|
||||
```
|
||||
|
||||
**NOTE: Always make sure 'PytubePP' and 'Pytubefix' is on the latest version to avoid issues (update them at least once a week) (Use the command below to update)**
|
||||
**UPDATE: Always make sure 'PytubePP' and 'Pytubefix' is on the latest version to avoid issues (update them at least once a week) (Use the command below to update)**
|
||||
|
||||
```
|
||||
pip install pytubefix pytubepp --upgrade
|
||||
@@ -108,20 +117,21 @@ 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:
|
||||
|
||||
| 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` `4320` `4320p` `8k` `mp3` (Pass any one of them) | Your chosen Default Stream via `-ds` flag |
|
||||
| -c | Choose preferred caption | YES | YES | All [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp) + auto generated ones + `none` for No Caption (Pass any one of them) eg: `en` for English | Your chosen Default Caption via `-dc` flag |
|
||||
| -i | Shows the video information like: Title, Author, Views, Publication Date, Duration, Available Download Streams and Captions | NO | YES | No parameters | No default |
|
||||
| -ls | Lists all available streams (video, audio, caption) (only for debuging purposes) | NO | YES | No parameters | No default |
|
||||
| -ri | Shows the video information in raw json format | NO | YES | No parameters | No default |
|
||||
| -jp | Shows raw json output in prettified view (with indentation: 4) (primarily used with -ri flag)| NO | YES | No parameters | No default |
|
||||
| -ds | Set default download stream | YES | NO | `144p` `240p` `360p` `480p` `720p` `1080p` `1440p` `2160p` `4320p` `mp3` `max` (Pass any one of them) | `max` |
|
||||
| -dc | Set default caption | YES | NO | All [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp) + auto generated ones + `none` for No Caption (Pass any one of them) eg: `en` for English | `none` |
|
||||
| -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 `PytubePP Downloads` folder in your System's `Downloads` folder |
|
||||
| -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 |
|
||||
| -ct | Clear temporary files (audio, video, thumbnail) of the failed, incomplete downloads | NO | NO | No parameters | No default |
|
||||
| Short Flag | Flag | Usage | Requires Parameter | Requires URL | Parameters | Default |
|
||||
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
||||
| -s | --stream | 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 |
|
||||
| -c | --caption | Choose preferred caption | YES | YES | All [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp) + auto generated ones + `none` for No Caption (Pass any one of them) eg: `en` for English | Your chosen Default Caption via `-dc` flag |
|
||||
| -i | --show-info | Shows the video information like: Title, Author, Views, Publication Date, Duration, Available Download Streams and Captions | NO | YES | No parameters | No default |
|
||||
| -ls | --list-stream | Lists all available streams (video, audio, caption) (only for debuging purposes) | NO | YES | No parameters | No default |
|
||||
| -ri | --raw-info | Shows the video information in raw json format | NO | YES | No parameters | No default |
|
||||
| -jp | --json-prettify | Shows raw json output in prettified view (with indentation: 4) (primarily used with -ri flag)| NO | YES | No parameters | No default |
|
||||
| -ds | --default-stream | Set default download stream | YES | NO | `144p` `240p` `360p` `480p` `720p` `1080p` `1440p` `2160p` `4320p` `mp3` `max` (Pass any one of them) | `max` |
|
||||
| -dc | --default-caption | Set default caption | YES | NO | All [ISO 639-1 Language Codes](https://www.w3schools.com/tags/ref_language_codes.asp) + auto generated ones + `none` for No Caption (Pass any one of them) eg: `en` for English | `none` |
|
||||
| -df | --download-folder | 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 `PytubePP Downloads` folder in your System's `Downloads` folder |
|
||||
| -r | --reset-default | Reset to default configuration (Download Folder, Default Stream) | NO | NO | No parameters | No default |
|
||||
| -sc | --show-config | Show all current user configurations | NO | NO | No parameters | No default |
|
||||
| -ct | --clear-temp | Clear temporary files (audio, video, thumbnail) of the failed, incomplete downloads | NO | NO | No parameters | No default |
|
||||
| -pi | --postinstall | Auto install all external dependencies (FFmpeg, Node.js) (in Windows, Linux - debian fedora arch, MacOS) | NO | NO | No parameters | No default |
|
||||
|
||||
### 🛠️ Contributing / Building from Source
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from .config import get_temporary_directory, load_config, update_config, reset_c
|
||||
from .download import download_progressive, download_nonprogressive, download_audio, progress
|
||||
from .postprocess import merge_audio_video, convert_to_mp3
|
||||
from .utils import get_version, clear_temp_files, is_valid_url, network_available, ffmpeg_installed, nodejs_installed, unpack_caption
|
||||
from .postinstaller import postinstall
|
||||
import appdirs, os, re, sys, argparse, json
|
||||
|
||||
class YouTubeDownloader:
|
||||
@@ -46,7 +47,7 @@ class YouTubeDownloader:
|
||||
if not nodejs_installed():
|
||||
print("\nWarning: Node.js is not installed or not found in PATH!")
|
||||
print("BotGuard poToken generation will not work properly without Node.js environment")
|
||||
print("Please install Node.js, read https://github.com/neosubhamoy/pytubepp#%EF%B8%8F-installation for instructions\n")
|
||||
print("Please install Node.js, by running: pytubepp --postinstall or read https://github.com/neosubhamoy/pytubepp#%EF%B8%8F-installation for manual instructions\n")
|
||||
|
||||
if is_valid_url(link):
|
||||
link = is_valid_url(link).group(1)
|
||||
@@ -295,7 +296,7 @@ class YouTubeDownloader:
|
||||
if not ffmpeg_installed():
|
||||
print("\nWarning: FFmpeg is not installed or not found in PATH!")
|
||||
print("Some core functionalities like video processing will not work properly without FFmpeg")
|
||||
print("Please install FFmpeg, read https://github.com/neosubhamoy/pytubepp#%EF%B8%8F-installation for instructions\n")
|
||||
print("Please install FFmpeg, by running: pytubepp --postinstall or read https://github.com/neosubhamoy/pytubepp#%EF%B8%8F-installation for manual instructions\n")
|
||||
sys.exit()
|
||||
|
||||
if self.set_video_info(link):
|
||||
@@ -388,6 +389,7 @@ def main():
|
||||
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('-ct', '--clear-temp', action='store_true', help='clear temporary files (audio, video, thumbnail files of the failed, incomplete downloads)')
|
||||
parser.add_argument('-pi', '--postinstall', action='store_true', help='auto install external dependencies (supported os: windows, linux - debian fedora arch, macos)')
|
||||
parser.add_argument('-v', '--version', action='store_true', help='show version number')
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -414,6 +416,8 @@ def main():
|
||||
print('\nVideo url supplied! ignoreing -ct flag...!!')
|
||||
if args.show_config:
|
||||
print('\nVideo url supplied! ignoreing -sc flag...!!')
|
||||
if args.postinstall:
|
||||
print('\nVideo url supplied! ignoreing -pi flag...!!')
|
||||
|
||||
# Handle info display flags
|
||||
if args.show_info:
|
||||
@@ -641,6 +645,9 @@ def main():
|
||||
if args.show_config:
|
||||
print(f'\ntempDIR: {downloader.temp_dir} (Unchangeable) \nconfigDIR: {downloader.config_dir} (Unchangeable)\ndownloadDIR: {downloader.download_dir}\ndefaultStream: {downloader.default_stream}\ndefaultCaption: {downloader.default_caption}\n')
|
||||
|
||||
if args.postinstall:
|
||||
postinstall()
|
||||
|
||||
if args.version:
|
||||
print(f'pytubepp {downloader.version}')
|
||||
|
||||
|
||||
130
pytubepp/postinstaller.py
Normal file
130
pytubepp/postinstaller.py
Normal file
@@ -0,0 +1,130 @@
|
||||
from .utils import ffmpeg_installed, nodejs_installed
|
||||
import subprocess, platform
|
||||
|
||||
def postinstall():
|
||||
os_type = platform.system().lower()
|
||||
package_manager = None
|
||||
|
||||
print("### PytubePP Post-Install Script ###\n")
|
||||
|
||||
print("Checking requirements...")
|
||||
ffmpeg_needed = not ffmpeg_installed()
|
||||
nodejs_needed = not nodejs_installed()
|
||||
|
||||
if ffmpeg_needed or nodejs_needed:
|
||||
if os_type == 'windows':
|
||||
version_info = platform.version().split('.')
|
||||
if int(version_info[0]) >= 10 and (int(version_info[1]) > 0 or int(version_info[2]) >= 1709):
|
||||
winget_check = subprocess.run(['winget', '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if winget_check.returncode == 0:
|
||||
print("OS: Windows (winget)")
|
||||
package_manager = 'winget' # Windows Package Manager
|
||||
else:
|
||||
print("OS: Windows (winget not enabled)")
|
||||
user_input = input("WinGet is not available. Do you want to enable winget? (Make sure to login to Windows before enabling) [yes/no]: ").strip().lower()
|
||||
if user_input in ['yes', 'y']:
|
||||
print("Enabling winget...")
|
||||
subprocess.run(['powershell', '-Command', 'Add-AppxPackage -RegisterByFamilyName -MainPackage Microsoft.DesktopAppInstaller_8wekyb3d8bbwe'])
|
||||
print("WinGet enabled successfully! Please restart your computer and re-run the post install script: pytubepp --postinstall")
|
||||
return
|
||||
else:
|
||||
print("Installation aborted! exiting...!!")
|
||||
return
|
||||
else:
|
||||
print("OS: Windows (winget not supported)")
|
||||
print("Unsupported Windows version! WinGet requires Windows 10 1709 (build 16299) or later, Please install dependencies manually...!!")
|
||||
return
|
||||
elif os_type == 'linux':
|
||||
# Determine the Linux distribution
|
||||
if subprocess.run(['command', '-v', 'apt'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
|
||||
print("OS: Linux (apt)")
|
||||
package_manager = 'apt' # APT for Debian/Ubuntu
|
||||
elif subprocess.run(['command', '-v', 'dnf'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
|
||||
print("OS: Linux (dnf)")
|
||||
distro_id = subprocess.run(['grep', '^ID=', '/etc/os-release'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
if distro_id.returncode == 0 and 'fedora' in distro_id.stdout.decode().strip() and ffmpeg_needed:
|
||||
user_input = input("Looks like you are using Fedora. Do you want to enable RPM Fusion free and nonfree repositories? (answer no if already enabled) [yes/no]: ").strip().lower()
|
||||
if user_input in ['yes', 'y']:
|
||||
print("Enabling RPM Fusion repositories...")
|
||||
fedora_version = subprocess.run(['rpm', '-E', '%fedora'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
if fedora_version.returncode == 0:
|
||||
fedora_version_str = fedora_version.stdout.decode().strip()
|
||||
subprocess.run(['sudo', 'dnf', 'install', f'https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-{fedora_version_str}.noarch.rpm', '-y'], check=True)
|
||||
subprocess.run(['sudo', 'dnf', 'install', f'https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-{fedora_version_str}.noarch.rpm', '-y'], check=True)
|
||||
else:
|
||||
print("Failed to retrieve Fedora version. Please install RPM Fusion repositories manually.")
|
||||
else:
|
||||
print("RPM Fusion repositories installation skipped...!!")
|
||||
package_manager = 'dnf' # DNF for Fedora
|
||||
elif subprocess.run(['command', '-v', 'pacman'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
|
||||
print("OS: Linux (pacman)")
|
||||
package_manager = 'pacman' # Pacman for Arch Linux
|
||||
else:
|
||||
print("OS: Linux (unknown)")
|
||||
print("Unsupported Linux distribution! Please install dependencies manually...!!")
|
||||
return
|
||||
elif os_type == 'darwin':
|
||||
homebrew_check = subprocess.run(['brew', '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
if homebrew_check.returncode == 0:
|
||||
print("OS: MacOS (brew)")
|
||||
package_manager = 'brew' # Homebrew for macOS
|
||||
else:
|
||||
print("OS: MacOS (brew not installed)")
|
||||
user_input = input("Homebrew is not installed. Do you want to install Homebrew? [yes/no]: ").strip().lower()
|
||||
if user_input in ['yes', 'y']:
|
||||
print("Installing Homebrew...")
|
||||
subprocess.run('/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"', shell=True)
|
||||
print("Homebrew installation completed! Please restart your mac and re-run the post install script: pytubepp --postinstall")
|
||||
return
|
||||
else:
|
||||
print("Installation aborted! exiting...!!")
|
||||
return
|
||||
else:
|
||||
print("Unsupported OS! Please install dependencies manually...!!")
|
||||
return
|
||||
|
||||
print("The following packages are about to be installed:")
|
||||
if ffmpeg_needed:
|
||||
print("- FFmpeg")
|
||||
if nodejs_needed:
|
||||
print("- Node.js")
|
||||
|
||||
user_input = input("Do you want to proceed with the installation? [yes/no]: ").strip().lower()
|
||||
if user_input not in ['yes', 'y']:
|
||||
print("Installation aborted! exiting...!!")
|
||||
return
|
||||
|
||||
if ffmpeg_needed:
|
||||
print("Installing FFmpeg...")
|
||||
install_ffmpeg(package_manager)
|
||||
if nodejs_needed:
|
||||
print("Installing Node.js...")
|
||||
install_nodejs(package_manager)
|
||||
else:
|
||||
print("Dependencies already satisfied! exiting...!!")
|
||||
|
||||
def install_ffmpeg(package_manager):
|
||||
if package_manager == 'winget':
|
||||
subprocess.run(['winget', 'install', 'ffmpeg'], check=True)
|
||||
elif package_manager == 'apt':
|
||||
subprocess.run(['sudo', 'apt', 'install', 'ffmpeg', '-y'], check=True)
|
||||
elif package_manager == 'dnf':
|
||||
subprocess.run(['sudo', 'dnf', 'install', 'ffmpeg', '-y'], check=True)
|
||||
elif package_manager == 'pacman':
|
||||
subprocess.run(['sudo', 'pacman', '-S', 'ffmpeg', '--noconfirm'], check=True)
|
||||
elif package_manager == 'brew':
|
||||
subprocess.run(['brew', 'install', 'ffmpeg'], check=True)
|
||||
print("FFmpeg installation completed")
|
||||
|
||||
def install_nodejs(package_manager):
|
||||
if package_manager == 'winget':
|
||||
subprocess.run(['winget', 'install', 'OpenJS.NodeJS.LTS'], check=True)
|
||||
elif package_manager == 'apt':
|
||||
subprocess.run(['sudo', 'apt', 'install', 'nodejs', '-y'], check=True)
|
||||
elif package_manager == 'dnf':
|
||||
subprocess.run(['sudo', 'dnf', 'install', 'nodejs', '-y'], check=True)
|
||||
elif package_manager == 'pacman':
|
||||
subprocess.run(['sudo', 'pacman', '-S', 'nodejs-lts-iron', 'npm', '--noconfirm'], check=True)
|
||||
elif package_manager == 'brew':
|
||||
subprocess.run(['brew', 'install', 'node'], check=True)
|
||||
print("Node.js installation completed")
|
||||
Reference in New Issue
Block a user