Najeebsk

IPTV-M3U-YOUTUBE-PREVIEW3.0.pyw

May 28th, 2024 (edited)
143
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.11 KB | None | 0 0
  1. import os
  2. import tkinter as tk
  3. from tkinter import ttk, filedialog, messagebox
  4. import requests
  5. import subprocess
  6. import threading
  7. import time
  8. import vlc
  9. from yt_dlp import YoutubeDL
  10. from googleapiclient.discovery import build
  11.  
  12. # Constants
  13. YOUTUBE_API_KEY = 'AIzaSyCzS7PGThVFxD83UFbfU5DOSZBMTxNpEeA'
  14. YOUTUBE_API_SERVICE_NAME = 'youtube'
  15. YOUTUBE_API_VERSION = 'v3'
  16.  
  17. # Functions for the main functionalities      
  18. def search_channels():
  19.     search_term = url_entry.get().lower()
  20.     if search_term.startswith("http"):
  21.         search_by_url(search_term)
  22.     else:
  23.         search_by_path_or_category(search_term)
  24.  
  25. def search_by_url(url):
  26.     try:
  27.         if os.path.exists(url):
  28.             with open(url, 'r', encoding='utf-8') as file:
  29.                 m3u_data = file.readlines()
  30.             process_m3u_data(m3u_data)
  31.         else:
  32.             response = requests.get(url)
  33.             if response.status_code == 200:
  34.                 try:
  35.                     m3u_data = response.text.split('\n')
  36.                 except UnicodeDecodeError:
  37.                     m3u_data = response.content.decode('ISO-8859-1').split('\n')
  38.                 process_m3u_data(m3u_data)
  39.             else:
  40.                 result_text.insert(tk.END, f"Error: Failed to fetch channel data. Status Code: {response.status_code}\n")
  41.     except Exception as e:
  42.         result_text.insert(tk.END, f"Error: {str(e)}\n")
  43.  
  44. def search_by_path_or_category(path):
  45.     try:
  46.         if os.path.exists(path):
  47.             try:
  48.                 with open(path, 'r', encoding='utf-8') as file:
  49.                     m3u_data = file.readlines()
  50.             except UnicodeDecodeError:
  51.                 with open(path, 'r', encoding='ISO-8859-1') as file:
  52.                     m3u_data = file.readlines()
  53.             process_m3u_data(m3u_data)
  54.         else:
  55.             selected_category = category_var.get()
  56.             if selected_category in category_urls:
  57.                 category_url = category_urls[selected_category]
  58.                 if category_url:
  59.                     search_by_url(category_url)
  60.                 else:
  61.                     result_text.insert(tk.END, f"Error: Category URL is not provided for {selected_category}\n")
  62.             else:
  63.                 result_text.insert(tk.END, f"Error: Category '{selected_category}' not found\n")
  64.     except Exception as e:
  65.         result_text.insert(tk.END, f"Error: {str(e)}\n")
  66.  
  67. def process_m3u_data(m3u_data):
  68.     result_text.delete(0, tk.END)
  69.     global channels_info
  70.     channels_info = {}
  71.     channel_name = None
  72.     for line in m3u_data:
  73.         if line.startswith('#EXTINF:'):
  74.             channel_name = line.split(',')[-1].strip()
  75.         elif line.startswith('http') and channel_name:
  76.             channels_info[channel_name] = line.strip()
  77.             result_text.insert(tk.END, channel_name)
  78.             channel_name = None
  79.  
  80. def search_youtube():
  81.     query = search_entry.get()
  82.     youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=YOUTUBE_API_KEY)
  83.     search_response = youtube.search().list(q=query, part='id,snippet', maxResults=250).execute()
  84.     result_text.delete(0, tk.END)
  85.     global channels_info
  86.     channels_info = {}
  87.     for item in search_response['items']:
  88.         if item['id']['kind'] == 'youtube#video':
  89.             video_title = item['snippet']['title']
  90.             video_id = item['id']['videoId']
  91.             video_url = f"https://www.youtube.com/watch?v={video_id}"
  92.             channels_info[video_title] = video_url
  93.             result_text.insert(tk.END, video_title)
  94.             print("Searching YouTube for:", query)
  95.  
  96. def play_selected_channel(event):
  97.     try:
  98.         selected_channel = result_text.get(tk.ACTIVE)
  99.         if selected_channel in channels_info:
  100.             url = channels_info[selected_channel]
  101.             if 'youtube.com' in url or 'youtu.be' in url:
  102.                 download_and_play_youtube(url)
  103.             elif os.path.exists(url):
  104.                 subprocess.Popen([r"C:\Program Files\VideoLAN\VLC\vlc.exe", url])
  105.     except (tk.TclError, KeyError):
  106.         pass
  107.  
  108. def download_and_play_youtube(url):
  109.     ydl_opts = {'format': 'best'}
  110.     try:
  111.         with YoutubeDL(ydl_opts) as ydl:
  112.             info_dict = ydl.extract_info(url, download=False)
  113.             video_url = info_dict['url']
  114.             play_vlc_stream(video_url)
  115.     except Exception as e:
  116.         messagebox.showerror("Error", f"Failed to extract video URL: {str(e)}")
  117.  
  118. def play_vlc_stream(stream_url):
  119.     media = instance.media_new(stream_url)
  120.     player.set_media(media)
  121.     player.set_hwnd(video_panel.winfo_id())
  122.     player.play()
  123.     update_slider()
  124.  
  125. def filter_channels(event=None):
  126.     keyword = search_entry.get().lower()
  127.     result_text.delete(0, tk.END)
  128.     for channel_name, url in channels_info.items():
  129.         if keyword in channel_name.lower():
  130.             result_text.insert(tk.END, channel_name)
  131.  
  132. def browse_file():
  133.     file_path = filedialog.askopenfilename(filetypes=[("M3U Files", "*.m3u"), ("All Files", "*.*")])
  134.     if file_path:
  135.         url_entry.delete(0, tk.END)
  136.         url_entry.insert(0, file_path)
  137.  
  138. def preview_selected_link():
  139.     selected_channel = result_text.get(tk.ACTIVE).strip()
  140.     if selected_channel in channels_info:
  141.         url = channels_info[selected_channel]
  142.         play_vlc_stream(url)
  143.     else:
  144.         messagebox.showerror("Error", "Selected text is not a valid URL.")
  145.      
  146. def stop_preview():
  147.     player.stop()
  148.     #preview_frame.pack_forget()
  149.  
  150. def capture_video():
  151.     try:
  152.         selected_channel = result_text.get(tk.ACTIVE).strip()
  153.         if selected_channel in channels_info:
  154.             url = channels_info[selected_channel]
  155.             filename = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[("MP4 files", "*.mp4")])
  156.             if filename:
  157.                 command = ['ffmpeg', '-y', '-i', url, '-t', '03:55:00', '-c', 'copy', filename]
  158.                 threading.Thread(target=lambda: subprocess.run(command)).start()
  159.                 messagebox.showinfo("Capturing", f"Capturing 03:55 minutes of video to {filename}")
  160.         else:
  161.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  162.     except tk.TclError:
  163.         messagebox.showerror("Error", "No text selected.")
  164.  
  165. def record_audio():
  166.     try:
  167.         selected_channel = result_text.get(tk.ACTIVE).strip()
  168.         if selected_channel in channels_info:
  169.             url = channels_info[selected_channel]
  170.             filename = filedialog.asksaveasfilename(defaultextension=".mp3", filetypes=[("MP3 files", "*.mp3")])
  171.             if filename:
  172.                 command = ['ffmpeg', '-y', '-i', url, '-f', 'mp3', '-c:a', 'libmp3lame', filename]
  173.                 global process
  174.                 process = subprocess.Popen(command)
  175.                 messagebox.showinfo("Recording", f"Recording audio to {filename}")
  176.         else:
  177.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  178.     except tk.TclError:
  179.         messagebox.showerror("Error", "No text selected.")
  180.  
  181. def stop_recording():
  182.     if process:
  183.         process.terminate()
  184.         messagebox.showinfo("Stopped", "Recording stopped")
  185.  
  186. def capture_screenshots():
  187.     if player.get_media():
  188.         filename_base = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG files", "*.png")])
  189.         if filename_base:
  190.             interval = 5
  191.             num_screenshots = 5
  192.             for i in range(num_screenshots):
  193.                 time.sleep(interval)
  194.                 filename = f"{filename_base}_{i + 1}.png"
  195.                 player.video_take_snapshot(0, filename, 0, 0)
  196.                 messagebox.showinfo("Capturing Screenshots", f"Captured {num_screenshots} screenshots every {interval} seconds to {filename_base}")
  197.  
  198. def update_slider():
  199.     length = player.get_length() / 1000
  200.     pos = player.get_position()
  201.     slider.set(pos)
  202.     current_time_label.config(text=time.strftime('%H:%M:%S', time.gmtime(player.get_time() / 1000)))
  203.     total_time_label.config(text=time.strftime('%H:%M:%S', time.gmtime(length)))
  204.     if player.is_playing():
  205.         root.after(1000, update_slider)
  206.  
  207. def on_slider_change(value):
  208.     player.set_position(float(value))
  209.  
  210. def play_in_vlc(url):
  211.     if 'youtube.com' in url or 'youtu.be' in url:
  212.         download_and_play_youtube(url)
  213.     else:
  214.         play_vlc_stream(url)
  215.  
  216. def set_volume(value):
  217.     volume = int(value)
  218.     if volume > 200:
  219.         volume = 200
  220.     player.audio_set_volume(volume)
  221.  
  222. def download_youtube():
  223.     try:
  224.         selected_channel = result_text.get(tk.ACTIVE).strip()
  225.         if selected_channel in channels_info:
  226.             url = channels_info[selected_channel]
  227.             filename = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[("All files", "*.*")])
  228.             if filename:
  229.                 quality = download_quality_var.get()
  230.                 if quality == 'Best':
  231.                     ydl_opts = {'format': 'bestvideo+bestaudio/best'}
  232.                 elif quality == 'Medium':
  233.                     ydl_opts = {'format': 'bestvideo[height<=480]+bestaudio/best[height<=480]'}
  234.                 elif quality == 'Low':
  235.                     ydl_opts = {'format': 'bestvideo[height<=240]+bestaudio/best[height<=240]'}
  236.                 elif quality == '360p':
  237.                     ydl_opts = {'format': 'bestvideo[height<=360]+bestaudio/best[height<=360]/mp4'}
  238.                 elif quality == '480p':
  239.                     ydl_opts = {'format': 'bestvideo[height<=480]+bestaudio/best[height<=480]/mp4'}
  240.                 elif quality == '720p':
  241.                     ydl_opts = {'format': 'bestvideo[height<=720]+bestaudio/best[height<=720]/mp4'}
  242.                 elif quality == 'MP3':
  243.                     ydl_opts = {'format': 'bestaudio/best', 'postprocessors': [{'key': 'FFmpegExtractAudio', 'preferredcodec': 'mp3', 'preferredquality': '192'}]}
  244.                 ydl_opts['outtmpl'] = filename
  245.                 with YoutubeDL(ydl_opts) as ydl:
  246.                     ydl.download([url])
  247.                 messagebox.showinfo("Download Complete", f"Downloaded video to {filename}")
  248.         else:
  249.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  250.     except tk.TclError:
  251.         messagebox.showerror("Error", "No text selected.")
  252.  
  253. def play_vlc():
  254.     selected_channel = result_text.get(tk.ACTIVE).strip()
  255.     if selected_channel in channels_info:
  256.         url = channels_info[selected_channel]
  257.         subprocess.Popen([r"C:\Program Files\VideoLAN\VLC\vlc.exe", url])
  258.     else:
  259.         messagebox.showerror("Error", "Selected text is not a valid URL.")
  260.  
  261. # GUI setup
  262. root = tk.Tk()
  263. root.title("Najeeb IPTV Channel And YOUTUBE Video")
  264. root.configure(bg="#4a4a4a")
  265. root.geometry("1000x680")
  266.  
  267. url_frame = tk.Frame(root, bg="#4a4a4a")
  268. url_frame.pack(pady=10, fill=tk.X)
  269.  
  270. url_label = tk.Label(url_frame, text="Enter URL or local path:", bg="#4a4a4a", fg="white")
  271. url_label.pack(side=tk.LEFT, padx=5)
  272. url_entry = ttk.Entry(url_frame, width=96)
  273. url_entry.pack(side=tk.LEFT, padx=5)
  274. search_button = tk.Button(url_frame, text="Search", command=search_channels, bg="#FFA500", fg="white")
  275. search_button.pack(side=tk.LEFT, padx=5)
  276. browse_button = tk.Button(url_frame, text="Browse M3U", command=browse_file, bg="#4a4a4a", fg="white")
  277. browse_button.pack(side=tk.LEFT, padx=5)
  278.  
  279. volume_frame = ttk.Frame(url_frame)
  280. volume_frame.pack(side=tk.LEFT, padx=10)
  281. volume_scale = tk.Scale(volume_frame, from_=0, to=200, orient="horizontal", command=set_volume, label="", bg="#4a4a4a", fg="white")
  282. volume_scale.set(50)
  283. volume_scale.pack(side=tk.LEFT, padx=5)
  284.  
  285. category_frame = ttk.Frame(root)
  286. category_frame.pack(pady=10, fill=tk.X)
  287.  
  288. ttk.Label(category_frame, text="Select Category:").pack(side=tk.LEFT)
  289. category_var = tk.StringVar()
  290. category_combo = ttk.Combobox(category_frame, textvariable=category_var)
  291. category_combo.pack(side=tk.LEFT, padx=5)
  292. category_combo['values'] = ['Sports', 'News', 'Movies', 'Songs']
  293. category_combo.bind("<<ComboboxSelected>>", lambda e: search_channels())
  294.  
  295. ttk.Button(category_frame, text="Search YouTube", command=search_youtube).pack(side=tk.LEFT, padx=5)
  296.  
  297. ttk.Label(category_frame, text="Search Word:").pack(side=tk.LEFT)
  298. search_entry = ttk.Entry(category_frame, width=90)
  299. search_entry.pack(pady=5)
  300. search_entry.bind("<KeyRelease>", filter_channels)
  301.  
  302. result_frame = ttk.Frame(root)
  303. result_frame.pack(fill=tk.BOTH, expand=True)
  304.  
  305. scrollbar = tk.Scrollbar(result_frame)
  306. scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  307.  
  308. result_text = tk.Listbox(result_frame, selectmode=tk.SINGLE)
  309. result_text.pack(fill=tk.BOTH, expand=True)
  310. result_text.bind("<Double-Button-1>", play_selected_channel)
  311.  
  312. scrollbar.config(command=result_text.yview)
  313.  
  314. control_frame = ttk.Frame(root)
  315. control_frame.pack(pady=10)
  316.  
  317. # Add the download quality dropdown and download button
  318. download_quality_var = tk.StringVar(value='Best')
  319. download_quality_combo = ttk.Combobox(control_frame, textvariable=download_quality_var, values=['Best', 'Medium', 'Low', '360p', '480p', '720p', 'MP3'])
  320. download_quality_combo.pack(side=tk.LEFT, padx=5)
  321. ttk.Button(control_frame, text="Download YT", command=download_youtube).pack(side=tk.LEFT, padx=5)
  322.  
  323. ttk.Button(control_frame, text="Preview", command=preview_selected_link).pack(side=tk.LEFT, padx=5)
  324. ttk.Button(control_frame, text="Stop Preview", command=stop_preview).pack(side=tk.LEFT, padx=5)
  325. ttk.Button(control_frame, text="Capture Video", command=capture_video).pack(side=tk.LEFT, padx=5)
  326. ttk.Button(control_frame, text="Record Audio", command=record_audio).pack(side=tk.LEFT, padx=5)
  327. ttk.Button(control_frame, text="Stop Recording", command=stop_recording).pack(side=tk.LEFT, padx=5)
  328. ttk.Button(control_frame, text="Capture Screenshots", command=capture_screenshots).pack(side=tk.LEFT, padx=5)
  329. ttk.Button(control_frame, text="Play VLC", command=play_vlc, style="TButton").pack(side=tk.LEFT, padx=5)
  330.  
  331. toggle_fullscreen_button = ttk.Button(control_frame, text="Toggle Fullscreen", command=lambda: toggle_fullscreen(preview_frame))
  332. toggle_fullscreen_button.pack(side=tk.LEFT, padx=5)
  333.  
  334. preview_frame = ttk.Frame(root)
  335. preview_frame.pack(fill=tk.BOTH, expand=True)
  336.  
  337. instance = vlc.Instance()
  338. player = instance.media_player_new()
  339. video_panel = ttk.Frame(preview_frame)
  340. video_panel.pack(fill=tk.BOTH, expand=True)
  341.  
  342. slider = ttk.Scale(preview_frame, from_=0, to=1, orient=tk.HORIZONTAL, command=on_slider_change)
  343. slider.pack(fill=tk.X)
  344.  
  345. current_time_label = ttk.Label(preview_frame, text="00:00:00")
  346. current_time_label.pack(side=tk.LEFT)
  347. total_time_label = ttk.Label(preview_frame, text="00:00:00")
  348. total_time_label.pack(side=tk.RIGHT)
  349.  
  350. channels_info = {}
  351.  
  352. def toggle_fullscreen(frame):
  353.     if not hasattr(toggle_fullscreen, "is_fullscreen"):
  354.         toggle_fullscreen.is_fullscreen = False
  355.     if toggle_fullscreen.is_fullscreen:
  356.         root.attributes('-fullscreen', False)
  357.         frame.pack(fill=tk.BOTH, expand=True)
  358.         result_frame.pack(fill=tk.BOTH, expand=True)
  359.         toggle_fullscreen.is_fullscreen = False
  360.     else:
  361.         root.attributes('-fullscreen', True)
  362.         frame.pack(fill=tk.BOTH, expand=True)
  363.         result_frame.pack_forget()
  364.         toggle_fullscreen.is_fullscreen = True
  365.  
  366. root.mainloop()
  367.  
Add Comment
Please, Sign In to add comment