Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update YouTube_playlist_downloader.py #1

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 120 additions & 106 deletions YouTube_playlist_downloader.py
Original file line number Diff line number Diff line change
@@ -1,156 +1,170 @@
import requests
import urllib.request
from bs4 import BeautifulSoup
import progressbar
from time import sleep


import asyncio
import aiohttp
import aiofiles
from concurrent.futures import ThreadPoolExecutor
from functools import lru_cache

# Create a session to reuse connections
session = requests.Session()
MAX_RETRIES = 3

# Cache network requests
@lru_cache(maxsize=128)
def cached_request(url):
for attempt in range(MAX_RETRIES):
try:
return session.get(url, timeout=10)
except requests.exceptions.RequestException as e:
if attempt == MAX_RETRIES - 1:
raise e
sleep(1)

# Function to display simple progress
def simple_progress(current, total):
print(f"Progress: {current}/{total} ({current/total:.1%})")

# Function to get download links from keepvid.com
def keepvid_download_link(start=1 , end=300):
fr = open('links.txt', 'r')
links = fr.read()
links = links.split("\n")
length=len(links)
print("Number of videos in the playlist "+str(length-1))
fkeep = open('keepvid.txt', 'w')
n=1
print("Getting download links...")
sleep(0.1)
bar = progressbar.ProgressBar(maxval=length-1, \
widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])
bar.start()
for link in links:
if n>=start and n<=end:
if link != "":
keepvid_url = 'http://keepvid.com/?url=' + link
href = download_link(keepvid_url)
bar.update(n)


fkeep.write(href + "\n")
n+=1
if n>end:
break
bar.finish()
sleep(1)
fkeep.close()
fr.close()

def downloading( num, user_input = 0):
# Use context manager for file operations
with open('links.txt', 'r') as fr:
links = fr.read().splitlines()

length = len(links)
print(f"Number of videos in the playlist {length-1}")

# Use ThreadPoolExecutor for parallel processing of download links
with ThreadPoolExecutor(max_workers=5) as executor:
valid_links = [link for link in links[start-1:end] if link]
futures = [executor.submit(download_link, f'http://keepvid.com/?url={link}')
for link in valid_links]

with open('keepvid.txt', 'w') as fkeep:
for i, future in enumerate(futures):
href = future.result()
simple_progress(start + i, length-1)
fkeep.write(f"{href}\n")

# Function to download videos
def downloading(num, user_input=0):
print('Downloading Videos....')
fr_title = open('vid_title.txt', 'r')
titles = fr_title.read()
titles = titles.split("\n")
fr_link = open('keepvid.txt', 'r')
links = fr_link.read()
links = links.split("\n")
max_index = len(links)-1

# Read video titles and links from files
with open('vid_title.txt', 'r') as fr_title, open('keepvid.txt', 'r') as fr_link:
titles = fr_title.read().splitlines()
links = fr_link.read().splitlines()
max_index = len(links) - 1
if user_input == 0:
user_input = num

# Use asyncio for concurrent downloads
selected_links = links[num-1:max_index]
selected_titles = titles[user_input-1:user_input-1+len(selected_links)]

loop = asyncio.get_event_loop()
results = loop.run_until_complete(download_multiple_videos(selected_links, selected_titles))

for i, success in enumerate(results):
if success:
print(f"{selected_titles[i]} -- [{num+i}/{max_index}] Downloaded")
else:
print(f"{selected_titles[i]} --Download Failed")

for link in links:
if num < (max_index+1):
if link[num-1] is not "no video found":
download_vid(links[num - 1], titles[user_input - 1])
print(titles[user_input-1] + " -- ["+str(num)+"/"+str(max_index)+"] Downloaded")
else:
print(titles[user_input-1] + " --Download Failed")

num += 1
user_input+=1

fr_link.close()
fr_title.close()
print("Download Complete.")


def download_vid(link, title):
name =str(title) + ".mp4"
urllib.request.urlretrieve(link,name)


# Function to download a video given a link and title
async def download_vid_async(link, title):
name = f"{title}.mp4"
async with aiohttp.ClientSession() as session:
async with session.get(link) as response:
if response.status == 200:
async with aiofiles.open(name, mode='wb') as f:
await f.write(await response.read())
return True
return False

async def download_multiple_videos(links, titles):
tasks = []
for link, title in zip(links, titles):
if link != "no video found":
task = asyncio.create_task(download_vid_async(link, title))
tasks.append(task)
return await asyncio.gather(*tasks)

# Function to get the download link from keepvid.com
def download_link(url):
source = requests.get(url)
plain_text = source.text
soup = BeautifulSoup(plain_text, "lxml")

a = 0
c=0
k=0
c = 0
k = 0

# Find the download link based on quality
for row in soup.findAll('td'):

qulity = str(row.string)
a+=1;
if qulity == '(Max 720p)':
c=((a-1)/4)+1
quality = str(row.string)
a += 1
if quality == '(Max 720p)':
c = ((a - 1) / 4) + 1
for link in soup.findAll('a', {'class': 'btn-outline'}):
k+=1

k += 1
if k == c:
href = link.get('href')

return href



break
elif qulity == '480p':
elif quality == '480p':
c = ((a - 1) / 4) + 1
for link in soup.findAll('a', {'class': 'btn-outline'}):
k += 1
# print(k)
if k == c:
href = link.get('href')
return href
break


if k > 0 :

if k > 0:
break
return 'no video found'

# Function to get all video links from a YouTube playlist
def download_link_youtube(url):
source = requests.get(url)
plain_text = source.text
soup = BeautifulSoup(plain_text, "lxml")
fw = open('links.txt', 'w')
for link in soup.findAll('a', {'class': 'playlist-video'}):
href = 'https://www.youtube.com' + link.get('href')

fw.write(href+"\n")

fw.close()
fw1 = open('vid_title.txt', 'w')
index=1
for title in soup.findAll('h4', {'class': 'yt-ui-ellipsis'}):
title_vid = title.string
title_vid=str(index)+"."+title_vid.strip()
fw1.write(title_vid + "\n")
index+=1

fw1.close()





response = cached_request(url)
soup = BeautifulSoup(response.text, "lxml")

# Use list comprehensions for better performance
links = ['https://www.youtube.com' + link.get('href')
for link in soup.findAll('a', {'class': 'playlist-video'})]

titles = [f"{i+1}.{title.string.strip()}"
for i, title in enumerate(soup.findAll('h4', {'class': 'yt-ui-ellipsis'}))]

# Write files using context managers
with open('links.txt', 'w') as fw:
fw.write('\n'.join(links))

with open('vid_title.txt', 'w') as fw1:
fw1.write('\n'.join(titles))

# Main script to handle user input and start the download process
print("Select your option : \nEnter 1 : To download playlist (Complete) form url\nEnter 2 : To resume your download.\nEnter 3 : For custom download")
option = input('Enter your option : ')
if option is '1':
if option == '1':
url = input('Enter URL of any video of Youtube Playlist : ')
download_link_youtube(url)
keepvid_download_link()
starting_index = 1
downloading(starting_index)
if option is '2':
starting_index =int( input('Enter the video number to start download from : '))
elif option == '2':
starting_index = int(input('Enter the video number to start download from : '))
downloading(starting_index)
if option is '3':
elif option == '3':
url = input('Enter URL of any video of Youtube Playlist : ')
starting_index = int(input('Enter the video number to start download from : '))
ending_index = int(input('Enter the video number to end at : '))
download_link_youtube(url)
keepvid_download_link(starting_index, ending_index)
downloading(1,starting_index)
downloading(1, starting_index)