Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import requests
- from bs4 import BeautifulSoup
- import tkinter as tk
- from tkinter import messagebox, filedialog, scrolledtext
- import re
- import vlc
- import yt_dlp
- import os
- import base64
- import webbrowser
- import threading
- from urllib.parse import urljoin
- class VideoDownloaderApp:
- def __init__(self):
- self.window = tk.Tk()
- self.window.title("Smart Video Downloader")
- self.attempted_urls = []
- self.scraped_urls = []
- self.all_collected_urls = []
- self.player = None
- self.download_path = None
- self.selected_code = "" # Ensure it starts as an empty string
- self.create_widgets()
- self.window.mainloop()
- def create_widgets(self):
- self.window.configure(bg='blue')
- self.url_label = tk.Label(self.window, text="Enter URL to Scrape:", bg='blue', fg='red')
- self.url_label.pack()
- self.url_entry = tk.Entry(self.window, width=50, bg='yellow', bd=2, fg='red', relief='solid')
- self.url_entry.pack()
- self.cleanse_button = tk.Button(self.window, text="Cleanse URL", command=self.cleanse_url_action,
- bg='green', fg='red', bd=2)
- self.cleanse_button.pack(pady=5)
- self.cleanse_all_button = tk.Button(self.window, text="Cleanse All URLs", command=self.cleanse_all_urls,
- bg='green', fg='red', bd=2)
- self.cleanse_all_button.pack(pady=5)
- self.scrape_button = tk.Button(self.window, text="Scrape for Videos", command=self.scrape_videos,
- bg='green', fg='red', bd=2)
- self.scrape_button.pack(pady=5)
- self.source_listbox = tk.Listbox(self.window, height=15, width=80, bd=2, relief='solid', bg='white', fg='red', selectbackground='lightblue')
- self.source_listbox.pack(pady=5)
- self.scan_button = tk.Button(self.window, text="Scan for All URLs", command=self.scan_urls,
- bg='green', fg='red', bd=2)
- self.scan_button.pack(pady=5)
- self.download_url_label = tk.Label(self.window, text="Enter or Select URL to Download:", bg='blue', fg='red')
- self.download_url_label.pack()
- self.download_url_entry = tk.Entry(self.window, width=50, bg='yellow', bd=2, fg='red', relief='solid')
- self.download_url_entry.pack()
- self.play_button = tk.Button(self.window, text="Play Selected Video or Entered URL", command=self.play_video,
- bg='green', fg='red', bd=2)
- self.play_button.pack(pady=5)
- self.save_info_button = tk.Button(self.window, text="Save Scrape Info as HTML", command=self.save_scrape_info_as_html,
- bg='green', fg='red', bd=2)
- self.save_info_button.pack(pady=5)
- self.download_button = tk.Button(self.window, text="Download Selected Videos", command=self.download_selected_videos,
- bg='green', fg='red', bd=2)
- self.download_button.pack(pady=5)
- self.execute_code_button = tk.Button(self.window, text="Execute Generated Code", command=self.execute_user_code,
- bg='green', fg='red', bd=2)
- self.execute_code_button.pack(pady=5)
- self.set_path_button = tk.Button(self.window, text="Set Download Directory", command=self.set_download_path,
- bg='green', fg='red', bd=2)
- self.set_path_button.pack(pady=5)
- self.download_combined_button = tk.Button(self.window, text="Download Combined HTML & JS", command=self.download_combined_content,
- bg='green', fg='red', bd=2)
- self.download_combined_button.pack(pady=5)
- self.code_output = scrolledtext.ScrolledText(self.window, wrap=tk.WORD, height=10, width=80, bg='orange', fg='red', bd=2, relief='solid')
- self.code_output.pack(pady=5)
- self.base64_options_label = tk.Label(self.window, text="Select Base64 Encoding:", bg='blue', fg='red')
- self.base64_options_label.pack(pady=5)
- self.base64_type_var = tk.StringVar(value="standard")
- self.base64_standard_radio = tk.Radiobutton(self.window, text="Standard Base64", variable=self.base64_type_var,
- value="standard", bg='blue', fg='red')
- self.base64_standard_radio.pack()
- self.base64_url_radio = tk.Radiobutton(self.window, text="URL Safe Base64", variable=self.base64_type_var,
- value="url_safe", bg='blue', fg='red')
- self.base64_url_radio.pack()
- def set_download_path(self):
- self.download_path = filedialog.askdirectory(title="Select Download Directory")
- if self.download_path and not os.path.isdir(self.download_path):
- messagebox.showerror("Error", "Invalid download path.")
- self.download_path = None
- elif self.download_path:
- messagebox.showinfo("Info", f"Download path set to: {self.download_path}")
- def cleanse_url_action(self):
- url = self.url_entry.get()
- cleaned_url = self.cleanse_url(url)
- if cleaned_url:
- messagebox.showinfo("Cleansed URL", f"Cleansed URL: {cleaned_url}")
- self.url_entry.delete(0, tk.END)
- self.url_entry.insert(0, cleaned_url)
- def cleanse_all_urls(self):
- # Store cleaned URLs for updates
- cleaned_scraped_urls = []
- cleaned_collected_urls = []
- # Cleanse scraped URLs
- for url in self.scraped_urls:
- cleaned_url = self.cleanse_url(url)
- if cleaned_url:
- cleaned_scraped_urls.append(cleaned_url)
- # Cleanse all collected URLs
- for url in self.all_collected_urls:
- cleaned_url = self.cleanse_url(url)
- if cleaned_url:
- cleaned_collected_urls.append(cleaned_url)
- # Update the listbox and internal lists
- self.scraped_urls = cleaned_scraped_urls
- self.all_collected_urls = cleaned_collected_urls
- self.source_listbox.delete(0, tk.END) # Clear the listbox
- self.source_listbox.insert(tk.END, "Cleaned Scraped URLs:")
- for cleaned_url in self.scraped_urls:
- self.source_listbox.insert(tk.END, cleaned_url)
- self.source_listbox.insert(tk.END, "Cleaned Collected URLs:")
- for cleaned_url in self.all_collected_urls:
- self.source_listbox.insert(tk.END, cleaned_url)
- def scan_urls(self):
- url = self.url_entry.get()
- if not url:
- messagebox.showwarning("Input Error", "Please enter a URL to scan.")
- return
- self.attempted_urls.append(url)
- cleaned_url = self.cleanse_url(url)
- if not cleaned_url:
- return
- try:
- response = requests.get(cleaned_url)
- response.raise_for_status()
- soup = BeautifulSoup(response.text, 'html.parser')
- urls = {urljoin(cleaned_url, link.get('href')) for link in soup.find_all('a', href=True)}
- self.source_listbox.delete(0, tk.END)
- self.source_listbox.insert(tk.END, f"Scanned URLs from {cleaned_url}:")
- for collected_url in urls:
- self.source_listbox.insert(tk.END, collected_url)
- self.all_collected_urls = list(urls)
- self.save_urls_to_file(self.all_collected_urls, "scanned_urls.txt")
- except Exception as e:
- messagebox.showerror("Error", f"Failed to scan the URL: {e}")
- def scrape_videos(self):
- url = self.url_entry.get()
- if not url:
- messagebox.showwarning("Input Error", "Please enter a URL.")
- return
- self.attempted_urls.append(url)
- cleaned_url = self.cleanse_url(url)
- if not cleaned_url:
- return
- try:
- response = requests.get(cleaned_url)
- response.raise_for_status()
- soup = BeautifulSoup(response.text, 'html.parser')
- scraped_video_urls = []
- scraped_video_urls += [source.get('src') for video in soup.find_all('video') for source in video.find_all('source')]
- scraped_video_urls += [iframe.get('src') for iframe in soup.find_all('iframe') if iframe.get('src')]
- self.source_listbox.delete(0, tk.END)
- self.source_listbox.insert(tk.END, f"Scraped URLs from {cleaned_url}:")
- for source in scraped_video_urls:
- self.source_listbox.insert(tk.END, source)
- for attempted_url in self.attempted_urls:
- if attempted_url not in self.source_listbox.get(0, tk.END):
- self.source_listbox.insert(tk.END, attempted_url)
- self.scraped_urls = scraped_video_urls
- self.save_urls_to_file(self.scraped_urls, "scraped_video_urls.txt")
- except Exception as e:
- messagebox.showerror("Error", f"Failed to scrape the URL: {e}")
- def save_urls_to_file(self, urls, default_filename):
- file_path = filedialog.asksaveasfilename(defaultextension=".txt", initialfile=default_filename,
- filetypes=[("Text Files", "*.txt")], title="Save URLs")
- if file_path:
- mode = 'a' if os.path.exists(file_path) else 'w'
- with open(file_path, mode, encoding='utf-8') as f:
- for url in urls:
- f.write(url + "\n")
- messagebox.showinfo("Info", f"URLs saved to {file_path}.")
- def play_video(self):
- # Check if a URL is entered or the first selection is valid
- entered_url = self.download_url_entry.get() or self.url_entry.get()
- if entered_url:
- # Create a VLC media player instance and play the video
- self.player = vlc.MediaPlayer(entered_url)
- if self.player is not None: # Ensure the player is created
- self.player.play()
- else:
- messagebox.showwarning("Video Error", "Failed to create media player with the entered URL.")
- return
- selected_indices = self.source_listbox.curselection()
- if not selected_indices:
- messagebox.showwarning("Selection Error", "Please select a video source or enter a URL.")
- return
- for index in selected_indices:
- video_url = self.source_listbox.get(index)
- # Check if video_url is valid and not empty
- if video_url: # Ensure video_url is not None or empty
- self.player = vlc.MediaPlayer(video_url)
- if self.player is not None: # Ensure the player is created
- self.player.play()
- else:
- messagebox.showwarning("Video Error", "Failed to create media player with the selected URL.")
- return
- else:
- messagebox.showwarning("Video Error", "The selected video URL is invalid.")
- def download_selected_videos(self):
- selected_indices = self.source_listbox.curselection()
- if not selected_indices:
- messagebox.showwarning("Selection Error", "Please select videos.")
- return
- if self.download_path is None:
- messagebox.showwarning("Download Path Error", "No download path set. Please set a download path first.")
- return
- video_url = self.source_listbox.get(selected_indices[0]) # Now taking the first selected video URL
- choice = messagebox.askquestion("Select Output Type", "Generate Base64 Output?", icon='question')
- if choice == 'yes':
- choice_base64 = self.base64_type_var.get() # Get selected base64 type
- self.selected_code = self.generate_output_code(video_url, output_format='base64', base64_type=choice_base64)
- else:
- choice_html = messagebox.askquestion("HTML Output", "Generate HTML Output?", icon='question')
- if choice_html == 'yes':
- self.selected_code = self.generate_output_code(video_url, output_format='html')
- else:
- self.selected_code = self.generate_downloader_code(video_url)
- if self.selected_code is None or self.selected_code == "":
- messagebox.showwarning("Code Generation Failed", "No code was generated.")
- return
- self.code_output.delete(1.0, tk.END)
- self.code_output.insert(tk.END, self.selected_code)
- def execute_user_code(self):
- if not self.selected_code:
- messagebox.showwarning("Code Error", "No previously selected code to execute.")
- return
- # Run the selected code directly
- threading.Thread(target=self.run_code, args=(self.selected_code,)).start()
- def generate_output_code(self, video_url, output_format='html', base64_type='standard'):
- if not self.download_path:
- messagebox.showwarning("Download Path Error", "Please set a download path before generating code.")
- return None
- if video_url is None: # Check video_url for None
- messagebox.showwarning("URL Error", "Video URL cannot be None.")
- return None
- download_path = self.download_path.replace('\\', '\\\\')
- if output_format == "base64":
- return f"""
- import yt_dlp
- import os
- import base64
- def download_video():
- video_url = '{video_url}'
- download_path = r'{download_path}'
- ydl_opts = {{
- 'format': 'best',
- 'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'),
- 'quiet': True,
- }}
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
- info_dict = ydl.extract_info(video_url, download=False)
- video_file_path = ydl.prepare_filename(info_dict)
- ydl.download([video_url])
- with open(video_file_path, 'rb') as video_file:
- encoded_string = base64.b64encode(video_file.read()).decode('utf-8')
- print("Base64 Encoded Video:", encoded_string)
- download_video()
- """
- elif output_format == "html":
- return f"""
- import yt_dlp
- import os
- def download_video():
- video_url = '{video_url}'
- download_path = r'{download_path}'
- ydl_opts = {{
- 'format': 'best',
- 'outtmpl': os.path.join(download_path, '%(title)s.%(ext)s'),
- 'quiet': True,
- }}
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
- info_dict = ydl.extract_info(video_url, download=False)
- video_file_path = ydl.prepare_filename(info_dict)
- try:
- ydl.download([video_url])
- html_output = f'<html><body><h1>Downloaded Video</h1><video width="320" height="240" controls>'
- html_output += f'<source src="{{video_file_path}}" type="video/mp4">No video support.</video></body></html>'
- with open(os.path.join(download_path, 'video_output.html'), 'w', encoding='utf-8') as html_file:
- html_file.write(html_output)
- except Exception as e:
- print(f"An error occurred: {{e}}")
- download_video()
- """
- else: # For downloader code
- return self.generate_downloader_code(video_url)
- def generate_downloader_code(self, video_url):
- if not self.download_path:
- messagebox.showwarning("Download Path Error", "Please set a download path before downloading.")
- return None
- if video_url is None: # Check if video_url is None before proceeding
- messagebox.showwarning("URL Error", "Video URL cannot be None.")
- return None
- download_path = self.download_path.replace('\\', '\\\\')
- downloader_code = f"""
- import yt_dlp
- import os
- def download_video():
- video_url = '{video_url}'
- ydl_opts = {{
- 'format': 'best',
- 'outtmpl': os.path.join(os.path.expanduser(r'{download_path}'), '%(title)s.%(ext)s'),
- }}
- try:
- with yt_dlp.YoutubeDL(ydl_opts) as ydl:
- ydl.download([video_url])
- except Exception as exception:
- print(f"An error occurred: {{exception}}")
- download_video()
- """
- return downloader_code
- def run_code(self, user_code):
- try:
- exec(user_code)
- except Exception as e:
- messagebox.showerror("Execution Error", f"Failed to execute the code: {e}")
- def download_combined_content(self):
- if not self.attempted_urls and not self.scraped_urls:
- messagebox.showwarning("No URLs", "No URLs available.")
- return
- base64_option = self.base64_type_var.get()
- combined_urls = []
- entered_url = self.url_entry.get()
- if entered_url:
- combined_urls.append(entered_url)
- combined_urls.extend(self.scraped_urls)
- try:
- html_content = "<html><body><h1>Combined Video URLs</h1><ul>"
- for video_url in combined_urls:
- html_content += f"<li>{video_url}</li>"
- html_content += "</ul></body></html>"
- if base64_option == "standard":
- base64_encoded_content = base64.b64encode(html_content.encode('utf-8')).decode('utf-8')
- elif base64_option == "url_safe":
- base64_encoded_content = base64.urlsafe_b64encode(html_content.encode('utf-8')).decode('utf-8')
- save_file_name = filedialog.asksaveasfilename(defaultextension=".b64", filetypes=[("Base64 Files", "*.b64")],
- title="Save Combined Base64 Encoded File")
- if save_file_name:
- with open(save_file_name, 'w', encoding='utf-8') as b64_file:
- b64_file.write(base64_encoded_content)
- messagebox.showinfo("Info", f"Combined Base64 encoded content saved to: {save_file_name}")
- except Exception as e:
- messagebox.showerror("Error", f"Failed to download combined content: {e}")
- def save_scrape_info_as_html(self):
- if not self.attempted_urls and not self.scraped_urls:
- messagebox.showwarning("No Data", "No URLs to save.")
- return
- html_content = "<html><body><h1>Video Scrape Info</h1><h2>Attempted URLs</h2><ul>"
- for attempted_url in self.attempted_urls:
- html_content += f"<li>{attempted_url}</li>"
- html_content += "</ul><h2>Scraped URLs</h2><ul>"
- for video_url in self.scraped_urls:
- html_content += f"<li>{video_url}</li>"
- html_content += "</ul></body></html>"
- file_path = filedialog.asksaveasfilename(defaultextension=".html", filetypes=[("HTML Files", "*.html")])
- if file_path:
- with open(file_path, 'w', encoding='utf-8') as f:
- f.write(html_content)
- messagebox.showinfo("Info", f"HTML file saved to {file_path}.")
- webbrowser.open(file_path)
- def cleanse_url(self, url):
- pattern = re.compile(
- r'^(?:http|ftp)s?://'
- r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|'
- r'localhost|'
- r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|'
- r'\[?[A-F0-9]*:[A-F0-9:]+\]?)'
- r'(?::\d+)?'
- r'(?:/?|[/?]\S+)$', re.IGNORECASE)
- if re.match(pattern, url):
- return url.split('?')[0]
- else:
- messagebox.showwarning("Invalid URL", "The provided URL is not valid.")
- return None
- if __name__ == "__main__":
- VideoDownloaderApp()
Comments
-
- https://github.com/soluzka/youtube-downloader/releases/tag/3.6.8.0
-
- https://github.com/soluzka/youtube-downloader/releases/tag/3.6
-
- 3.0 and 3.6.8.0
Add Comment
Please, Sign In to add comment