Compare commits
10 Commits
7dffdbbb0b
...
dbbf7cd80f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbbf7cd80f | ||
|
|
8eae0b9181 | ||
|
|
6f3ba8c38f | ||
|
|
66b3c1fa6b | ||
|
|
2a13613d9a | ||
|
|
f8e54b7b32 | ||
|
|
af3317cf9f | ||
|
|
4f11cd4ae7 | ||
|
|
3cdb0b495c | ||
|
|
124c501da8 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
*.pyc
|
||||
*.pyc
|
||||
19
README.md
19
README.md
@@ -5,7 +5,8 @@ PornHub-dl is a Python tool for downloading PornHub video/playlist.
|
||||
## Requirements
|
||||
```bash
|
||||
Python 3.7 or later
|
||||
ffmpeg
|
||||
VPN or any anti - Deep Packet Inspection (if your ISP blocks Pornhub) ^-^
|
||||
|
||||
```
|
||||
## Installation
|
||||
|
||||
@@ -32,9 +33,11 @@ optional arguments:
|
||||
|
||||
# download single video from PornHub
|
||||
pornhub_dl.py --url https://www.pornhub.com/view_video.php?viewkey=ph5b11c7f2ddecc
|
||||
# download all videos (most viewed) from model CarryLight of PornHub
|
||||
# download first 30 videos (default = best) from model CarryLight
|
||||
pornhub_dl.py --url https://www.pornhub.com/model/carrylight --playlist --limit 30
|
||||
# download all videos (most viewed) from model CarryLight
|
||||
pornhub_dl.py --url https://www.pornhub.com/model/carrylight --playlist most-viewed
|
||||
# download first 30 videos (most viewed) from model CarryLight of PornHub
|
||||
# download first 30 videos (most viewed) from model CarryLight
|
||||
pornhub_dl.py --url https://www.pornhub.com/model/carrylight --playlist most-viewed --limit 30
|
||||
```
|
||||
|
||||
@@ -47,12 +50,16 @@ Please make sure to update tests as appropriate.
|
||||
[MIT](https://choosealicense.com/licenses/mit/)
|
||||
|
||||
## Special thanks
|
||||
YouTube-DL (the world's most powerful tool)
|
||||
```
|
||||
YouTube-DL (the world's most powerful tool)
|
||||
|
||||
aria2c (a f*ckinn lightweight multi-source command-line download utility)
|
||||
|
||||
PyFiglet (simple and beauty)
|
||||
|
||||
BeautifulSoup4
|
||||
@ValdikSS for his Deep Packet Inspection circumvention utility (github.com/ValdikSS/GoodbyeDPI)
|
||||
|
||||
@mariosemes for his PornHub-downloader (github.com/mariosemes/PornHub-downloader-python)
|
||||
```
|
||||
|
||||
# from tnt2402 with <3
|
||||
# from tnt2402 with <3
|
||||
|
||||
Binary file not shown.
BIN
aria2c.exe
Normal file
BIN
aria2c.exe
Normal file
Binary file not shown.
156
lib_pornhub.py
156
lib_pornhub.py
@@ -10,18 +10,22 @@ import json
|
||||
from time import sleep
|
||||
from tqdm import tqdm
|
||||
#############
|
||||
|
||||
|
||||
def ascii_banner(text):
|
||||
print('\n\n########################################################\n\n\n')
|
||||
ascii_banner = pyfiglet.figlet_format(text)
|
||||
print(ascii_banner)
|
||||
print(ascii_banner)
|
||||
################################
|
||||
|
||||
duration = 1000
|
||||
download_dir = os.getcwd()
|
||||
|
||||
# duration = 1000
|
||||
download_dir = os.getcwd()
|
||||
|
||||
|
||||
def ph_config_dl_dir(dir):
|
||||
global download_dir
|
||||
if (dir != None):
|
||||
if (dir != None):
|
||||
download_dir = dir
|
||||
print("Output directory: " + download_dir + "\model\\")
|
||||
if (os.path.exists(download_dir) != True):
|
||||
@@ -31,39 +35,63 @@ def ph_config_dl_dir(dir):
|
||||
if (os.path.exists(download_dir) != True):
|
||||
os.mkdir(download_dir)
|
||||
|
||||
### Main functions
|
||||
|
||||
def run_command(command):
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=False)
|
||||
pbar = tqdm(total=100, unit=" percents")
|
||||
state = 0
|
||||
current_frag = 0
|
||||
total_frag = 1
|
||||
result_txt = ''
|
||||
while True:
|
||||
output = process.stdout.readline().decode("utf-8")
|
||||
if "[download] 100" in output:
|
||||
result_txt = 'Result: ' + output.split("[download]")[1].strip()
|
||||
|
||||
if output == '' and process.poll() is not None:
|
||||
break
|
||||
|
||||
if 'Total fragments' in output:
|
||||
total_frag = int(output.split(':')[1].strip())
|
||||
if 'FILE:' in output:
|
||||
current_frag = int(output.split('.part-Frag')[1].strip())
|
||||
current_per = int(current_frag / total_frag * 100)
|
||||
pbar.update(current_per - state)
|
||||
state = current_per
|
||||
sleep(0.00001)
|
||||
pbar.update(100 - state)
|
||||
pbar.close()
|
||||
rc = process.poll()
|
||||
if result_txt != '': print(result_txt)
|
||||
return rc
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(0)
|
||||
|
||||
# Main functions
|
||||
|
||||
|
||||
def ph_check_valid_pornhub_url(url):
|
||||
if ('pornhub.com' not in url):
|
||||
print('Invalid Pornhub URL')
|
||||
sys.exit()
|
||||
if url.startswith('pornhub.com'):
|
||||
url = 'https://www.' + url
|
||||
return url
|
||||
return url
|
||||
|
||||
|
||||
def download_video(url, filename):
|
||||
global duration
|
||||
# global duration
|
||||
state = 0
|
||||
print('[+] Save as: ' + filename + '\n')
|
||||
try:
|
||||
pbar = tqdm(total=duration, unit= " fragments")
|
||||
p = subprocess.Popen(['.\youtube-dl', '--no-warnings', '--hls-prefer-ffmpeg', '--ffmpeg-location', os.getcwd(), '-o', filename, url], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell = False)
|
||||
for line in iter(p.stdout.readline, b''):
|
||||
line = line.decode('utf-8').strip()
|
||||
# if ("[ffmpeg] " in line):
|
||||
# print('\n' + line.strip())
|
||||
if "time=" in line:
|
||||
time = line.split("time=")[1][:8]
|
||||
hour, minute, second = time.split(":")
|
||||
progress_time = 3600 * int(hour) + 60 * int(minute) + int(second)
|
||||
pbar.update(progress_time - state)
|
||||
state = progress_time
|
||||
sleep(0.001)
|
||||
elif "Failed" in line:
|
||||
print("\nFailed while processing")
|
||||
sys.exit(1)
|
||||
pbar.update(duration)
|
||||
pbar.close()
|
||||
# print("\n[$] Video download successfully!")
|
||||
|
||||
run_command(['.\yt-dlp', '--downloader', 'aria2c', '--downloader-args',
|
||||
'aria2c:-x 8 --log-level=info --file-allocation=none --summary-interval=1', '--no-warnings', '--newline', '-o', filename, url])
|
||||
|
||||
print("[$] Video download successfully!")
|
||||
except KeyboardInterrupt:
|
||||
os.kill(p.pid, signal.CTRL_C_EVENT)
|
||||
sys.exit()
|
||||
@@ -74,65 +102,88 @@ def fix_title(s):
|
||||
deny_char = ['\\', '/', '.', '?', '*', ':', '!']
|
||||
for i in deny_char:
|
||||
decoded_unicode = decoded_unicode.replace(i, '')
|
||||
return decoded_unicode
|
||||
return decoded_unicode.strip()
|
||||
|
||||
|
||||
def check_output_dir(model_name):
|
||||
global download_dir
|
||||
download_dir = download_dir
|
||||
download_dir = download_dir
|
||||
if (os.path.exists(download_dir + model_name) != True):
|
||||
os.mkdir(download_dir+model_name)
|
||||
|
||||
|
||||
def ph_download_video(url, model_name, filename):
|
||||
|
||||
try:
|
||||
|
||||
try:
|
||||
check_output_dir(model_name)
|
||||
# filename = os.path.join(download_dir, model_name, fix_title(str(video["title"])) + '.' + str(video['ext']))
|
||||
download_video(url, filename)
|
||||
except:
|
||||
print('Cannot download video')
|
||||
|
||||
|
||||
|
||||
def ph_download_playlist(url, model_name, limit):
|
||||
global download_dir
|
||||
global duration
|
||||
# global duration
|
||||
check_output_dir(model_name)
|
||||
|
||||
if (limit != 0):
|
||||
print("[!] Limit: {} videos".format(limit))
|
||||
|
||||
# tmp_playlist download
|
||||
print('... Getting playlist information...')
|
||||
playlist_download_command = [".\youtube-dl", "-j", "--flat-playlist", "--no-check-certificate", url]
|
||||
res = subprocess.run(playlist_download_command, capture_output=True, text=True).stdout.split("\n")
|
||||
if (limit != 0 ):
|
||||
print("[!] Limit: {} videos".format(limit))
|
||||
try:
|
||||
playlist_download_command = [".\yt-dlp", "-j",
|
||||
"--flat-playlist", "--no-check-certificate", url]
|
||||
res = subprocess.run(playlist_download_command,
|
||||
capture_output=True, text=True).stdout.split("\n")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
count = 0
|
||||
|
||||
if res == ['']:
|
||||
print("Cannot download playlist information!")
|
||||
sys.exit(1)
|
||||
print("Playlist has {} videos".format(len(res)))
|
||||
|
||||
for i in range(len(res) - 1):
|
||||
if (count == limit and limit != 0):
|
||||
break
|
||||
sys.exit()
|
||||
try:
|
||||
video_dict = ast.literal_eval(res[i])
|
||||
# print(res[i])
|
||||
# video_dict = ast.literal_eval(res[i])
|
||||
video_dict = json.loads(res[i])
|
||||
url = video_dict['url']
|
||||
p = subprocess.Popen(['.\youtube-dl', '--no-warnings', '--dump-json', '--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell = True)
|
||||
p = subprocess.Popen(['.\yt-dlp', '--no-warnings', '--dump-json',
|
||||
'--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell=True)
|
||||
output = p.communicate()[0]
|
||||
info = json.loads(output.decode('utf-8'))
|
||||
duration = int(info['duration'])
|
||||
filename = os.path.join(download_dir, model_name, fix_title(str(info["title"])) + '.' + str(info['ext']))
|
||||
print("\n\n==========================================\n[+] File #{}: {}".format(count, fix_title(str(info["title"])) + '.' + str(info['ext'])))
|
||||
# duration = int(info['duration'])
|
||||
filename = os.path.join(download_dir, model_name, fix_title(
|
||||
str(info["title"])) + '.' + str(info['ext']))
|
||||
print("\n\n==========================================\n[+] File #{}: {}".format(
|
||||
count, fix_title(str(info["title"])) + '.' + str(info['ext'])))
|
||||
ph_download_video(url, model_name, filename)
|
||||
count = count + 1
|
||||
except KeyboardInterrupt:
|
||||
print("Cannot download video")
|
||||
sys.exit()
|
||||
|
||||
|
||||
def fix_url(url, type):
|
||||
url = ph_check_valid_pornhub_url(url)
|
||||
|
||||
if '/model/' not in url:
|
||||
p = subprocess.Popen(['.\youtube-dl', '--no-warnings', '--dump-json', '--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell = True)
|
||||
p = subprocess.Popen(['.\yt-dlp', '--no-warnings', '--dump-json',
|
||||
'--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell=True)
|
||||
output = p.communicate()[0]
|
||||
info = json.loads(output.decode('utf-8'))
|
||||
model_name = info['uploader']
|
||||
else:
|
||||
model_name = url.split('/model/')[1].split('/')[0]
|
||||
|
||||
|
||||
url = 'www.pornhub.com/model/' + model_name + '/videos'
|
||||
if (type == 'most-viewed'):
|
||||
url = url + '?o=mv'
|
||||
@@ -143,20 +194,25 @@ def fix_url(url, type):
|
||||
print("[+] Model: " + model_name)
|
||||
return (url, model_name)
|
||||
|
||||
|
||||
def ph_get_video(url):
|
||||
global duration
|
||||
# global duration
|
||||
url = ph_check_valid_pornhub_url(url)
|
||||
|
||||
p = subprocess.Popen(['.\youtube-dl', '--no-warnings', '--dump-json', '--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell = True)
|
||||
|
||||
p = subprocess.Popen(['.\yt-dlp', '--no-warnings', '--dump-json',
|
||||
'--skip-download', url], stdout=subprocess.PIPE, stderr=None, shell=True)
|
||||
output = p.communicate()[0]
|
||||
info = json.loads(output.decode('utf-8'))
|
||||
model_name = info['uploader']
|
||||
duration = int(info['duration'])
|
||||
filename = os.path.join(download_dir, model_name, fix_title(str(info["title"])) + '.' + str(info['ext']))
|
||||
# duration = int(info['duration'])
|
||||
filename = os.path.join(download_dir, model_name, fix_title(
|
||||
str(info["title"])) + '.' + str(info['ext']))
|
||||
print("[+] Model: " + model_name)
|
||||
print("[+] Filename: " + fix_title(str(info["title"])) + '.' + str(info['ext']))
|
||||
print("[+] Filename: " + fix_title(str(info["title"])) +
|
||||
'.' + str(info['ext']))
|
||||
ph_download_video(url, model_name, filename)
|
||||
|
||||
|
||||
def ph_get_playlist(url, type, limit):
|
||||
url, model_name = fix_url(url, type)
|
||||
ph_download_playlist(url, model_name, limit)
|
||||
ph_download_playlist(url, model_name, limit)
|
||||
|
||||
@@ -16,7 +16,7 @@ else:
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--url', type=str, help = 'URL of Pornhub video')
|
||||
parser.add_argument('--playlist', choices = ['most-viewed', 'best', 'top-rated', 'longest'], type=str, help = 'Optional ordering of videos')
|
||||
parser.add_argument('--playlist', nargs='?', const='best', choices = ['most-viewed', 'best', 'top-rated', 'longest'], help = 'Optional ordering of videos')
|
||||
parser.add_argument('--limit', type=int, help = 'Maximum number of videos', default=0)
|
||||
parser.add_argument('--dir', type=str, help = 'Output directory')
|
||||
args = parser.parse_args()
|
||||
|
||||
BIN
youtube-dl.exe
BIN
youtube-dl.exe
Binary file not shown.
BIN
yt-dlp.exe
Normal file
BIN
yt-dlp.exe
Normal file
Binary file not shown.
Reference in New Issue
Block a user