Advertisement
Najeebsk

IPTV2.0.pyw

Jul 21st, 2024
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 15.63 KB | None | 0 0
  1. import os
  2. import tkinter as tk
  3. from tkinter import ttk, filedialog, messagebox
  4. import vlc
  5. import subprocess
  6. import threading
  7.  
  8. # Constants
  9. CHANNELS_FOLDER = 'CHANNELS'
  10. VLC_PATH = r"C:\Program Files\VideoLAN\VLC\vlc.exe"
  11. WGET_PATH = r"C:\CMDER\APP\wget.exe"  # Update this with the correct path to wget.exe
  12. FFMPEG_PATH = r"C:\CMDER\APP\ffmpeg.exe"  # Update this with the correct path to ffmpeg.exe
  13.  
  14. # Initialize VLC
  15. instance = vlc.Instance('--verbose 2')
  16. player = instance.media_player_new()
  17.  
  18. # Initialize variables
  19. is_dragging_slider = False
  20. is_muted = False
  21.  
  22. class NajeebChannelPlayer(tk.Tk):
  23.     def __init__(self):
  24.         super().__init__()
  25.  
  26.         self.title("Najeeb IPTV Channel Player")
  27.         self.geometry("1000x600")
  28.         self.configure(bg='#2E2E2E')
  29.        
  30.         self.channels_info = {}
  31.         self.process = None
  32.         self.is_fullscreen = False
  33.  
  34.         self.create_widgets()
  35.         self.load_channels_from_folder()
  36.         self.update_video_slider()
  37.  
  38.     def create_widgets(self):
  39.         self.control_frame = ttk.Frame(self, style="TFrame")
  40.         self.control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  41.  
  42.         self.search_entry = ttk.Entry(self.control_frame, width=50)
  43.         self.search_entry.pack(side=tk.LEFT, padx=5, pady=5)
  44.         search_button = ttk.Button(self.control_frame, text="Search", command=self.search_channels)
  45.         search_button.pack(side=tk.LEFT, padx=5, pady=5)
  46.  
  47.         filter_button = ttk.Button(self.control_frame, text="Filter", command=self.filter_channels)
  48.         filter_button.pack(side=tk.LEFT, padx=5, pady=5)
  49.  
  50.         copy_button = ttk.Button(self.control_frame, text="Copy URL", command=self.copy_selected_url)
  51.         copy_button.pack(side=tk.LEFT, padx=5, pady=5)
  52.  
  53.         preview_button = ttk.Button(self.control_frame, text="Preview", command=self.preview_selected_channel)
  54.         preview_button.pack(side=tk.LEFT, padx=5, pady=5)
  55.  
  56.         stop_button = ttk.Button(self.control_frame, text="Stop Preview", command=self.stop_preview)
  57.         stop_button.pack(side=tk.LEFT, padx=5, pady=5)
  58.  
  59.  
  60.         # Volume and Mute Controls
  61.         volume_frame = ttk.Frame(self.control_frame, style="TFrame")
  62.         volume_frame.pack(side=tk.LEFT, padx=5, pady=5)
  63.  
  64.         volume_label = ttk.Label(volume_frame, text="Volume")
  65.         volume_label.pack(side=tk.LEFT)
  66.  
  67.         volume_slider = ttk.Scale(volume_frame, from_=0, to=100, orient=tk.HORIZONTAL, command=self.set_volume)
  68.         volume_slider.set(50)  # Default volume
  69.         volume_slider.pack(side=tk.LEFT, padx=5)
  70.  
  71.         self.mute_button = ttk.Button(volume_frame, text="Mute", command=self.mute_unmute)
  72.         self.mute_button.pack(side=tk.LEFT, padx=5)
  73.  
  74.         # Additional Buttons
  75.         self.additional_buttons_frame = ttk.Frame(self, style="TFrame")
  76.         self.additional_buttons_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  77.  
  78.         capture_video_button = ttk.Button(self.additional_buttons_frame, text="Capture Video", command=self.capture_video)
  79.         capture_video_button.pack(side=tk.LEFT, padx=5, pady=5)
  80.  
  81.         record_audio_button = ttk.Button(self.additional_buttons_frame, text="Record Audio", command=self.record_audio)
  82.         record_audio_button.pack(side=tk.LEFT, padx=5, pady=5)
  83.  
  84.         stop_record_button = ttk.Button(self.additional_buttons_frame, text="Stop Recording", command=self.stop_recording)
  85.         stop_record_button.pack(side=tk.LEFT, padx=5, pady=5)
  86.  
  87.         screenshot_button = ttk.Button(self.additional_buttons_frame, text="Capture Screenshots", command=self.capture_screenshots)
  88.         screenshot_button.pack(side=tk.LEFT, padx=5, pady=5)
  89.  
  90.         fullscreen_button = ttk.Button(self.additional_buttons_frame, text="Full Screen", command=self.toggle_fullscreen)
  91.         fullscreen_button.pack(side=tk.LEFT, padx=5, pady=5)
  92.  
  93.         download_button = ttk.Button(self.additional_buttons_frame, text="Download with wget", command=self.download_video)
  94.         download_button.pack(side=tk.LEFT, padx=5, pady=5)
  95.  
  96.         download_ffmpeg_button = ttk.Button(self.additional_buttons_frame, text="Download with ffmpeg", command=self.download_with_ffmpeg)
  97.         download_ffmpeg_button.pack(side=tk.LEFT, padx=5, pady=5)
  98.  
  99.         # Video control slider
  100.         self.video_slider = ttk.Scale(self, from_=0, to=1000, orient=tk.HORIZONTAL)
  101.         self.video_slider.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
  102.         self.video_slider.bind("<ButtonPress-1>", self.slider_pressed)
  103.         self.video_slider.bind("<ButtonRelease-1>", self.slider_released)
  104.  
  105.         self.result_frame = ttk.Frame(self, style="TFrame")
  106.         self.result_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=1, pady=5)
  107.  
  108.         self.result_text = tk.Listbox(self.result_frame, width=30, height=25, selectmode=tk.SINGLE, bg='#FFFFFF', fg='#000000')
  109.         self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=False)
  110.  
  111.         # Add scrollbars
  112.         vsb = ttk.Scrollbar(self.result_frame, orient="vertical", command=self.result_text.yview)
  113.         vsb.pack(side=tk.RIGHT, fill="y")
  114.         self.result_text.configure(yscrollcommand=vsb.set)
  115.  
  116.         self.result_text.bind('<Double-1>', self.play_selected_channel)
  117.  
  118.         self.video_frame = tk.Frame(self, bg='#000000')
  119.         self.video_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=5)
  120.  
  121.         self.video_panel = tk.Frame(self.video_frame, bg='#000000')
  122.         self.video_panel.pack(fill=tk.BOTH, expand=True)
  123.  
  124.         self.bind("<Motion>", self.show_controls_on_mouse_move)
  125.  
  126.     def load_channels_from_folder(self):
  127.         try:
  128.             files = [f for f in os.listdir(CHANNELS_FOLDER) if f.endswith('.txt')]
  129.             all_channels = []
  130.             for file in files:
  131.                 file_path = os.path.join(CHANNELS_FOLDER, file)
  132.                 with open(file_path, 'r', encoding='utf-8') as f:
  133.                     all_channels.extend(f.readlines())
  134.             self.process_text_data(all_channels)
  135.         except FileNotFoundError:
  136.             messagebox.showerror("Error", f"The folder '{CHANNELS_FOLDER}' does not exist.")
  137.         except PermissionError:
  138.             messagebox.showerror("Error", f"Permission denied while accessing '{CHANNELS_FOLDER}'.")
  139.         except Exception as e:
  140.             self.result_text.insert(tk.END, f"Error loading channels from folder: {str(e)}\n")
  141.  
  142.     def process_text_data(self, text_data):
  143.         self.result_text.delete(0, tk.END)
  144.         self.channels_info = {}
  145.         for line in text_data:
  146.             line = line.strip()
  147.             if line:
  148.                 if "http" in line:
  149.                     # Find the URL by splitting on space
  150.                     parts = line.split(' ', 1)
  151.                     if len(parts) == 2:
  152.                         channel_name = parts[0].strip()
  153.                         url = parts[1].strip()
  154.                         self.channels_info[channel_name] = url
  155.                         self.result_text.insert(tk.END, channel_name)
  156.  
  157.     def search_channels(self):
  158.         search_term = self.search_entry.get().lower()
  159.         self.result_text.delete(0, tk.END)
  160.         for channel_name, url in self.channels_info.items():
  161.             if search_term in channel_name.lower():
  162.                 self.result_text.insert(tk.END, channel_name)
  163.  
  164.     def filter_channels(self):
  165.         search_term = self.search_entry.get().lower()
  166.         self.result_text.delete(0, tk.END)
  167.         for channel_name, url in self.channels_info.items():
  168.             if search_term in channel_name.lower() or search_term in url.lower():
  169.                 self.result_text.insert(tk.END, channel_name)
  170.  
  171.     def play_selected_channel(self, event):
  172.         try:
  173.             selected_channel = self.result_text.get(tk.ACTIVE)
  174.             if selected_channel in self.channels_info:
  175.                 url = self.channels_info[selected_channel]
  176.                 subprocess.Popen([VLC_PATH, url])
  177.         except (tk.TclError, KeyError):
  178.             pass
  179.  
  180.     def preview_selected_channel(self):
  181.         try:
  182.             selected_channel = self.result_text.get(tk.ACTIVE)
  183.             if selected_channel in self.channels_info:
  184.                 url = self.channels_info[selected_channel]
  185.                 self.play_vlc_stream(url)
  186.         except (tk.TclError, KeyError):
  187.             pass
  188.  
  189.     def play_vlc_stream(self, stream_url):
  190.         media = instance.media_new(stream_url)
  191.         player.set_media(media)
  192.         player.set_hwnd(self.video_panel.winfo_id())
  193.         player.play()
  194.         self.update_video_slider()
  195.  
  196.     def slider_pressed(self, event):
  197.         global is_dragging_slider
  198.         is_dragging_slider = True
  199.  
  200.     def slider_released(self, event):
  201.         global is_dragging_slider
  202.         is_dragging_slider = False
  203.         player.set_time(int(self.video_slider.get()))
  204.  
  205.     def update_video_slider(self):
  206.         if player and not is_dragging_slider:
  207.             position = player.get_time() / 1000.0
  208.             self.video_slider.set(position * 1000.0)
  209.         self.after(1000, self.update_video_slider)
  210.  
  211.     def stop_preview(self):
  212.         if player:
  213.             player.stop()
  214.  
  215.     def copy_selected_url(self):
  216.         selected_channel = self.result_text.get(tk.ACTIVE).strip()
  217.         if selected_channel in self.channels_info:
  218.             url = self.channels_info[selected_channel]
  219.             self.clipboard_clear()
  220.             self.clipboard_append(url)
  221.             messagebox.showinfo("Copied", f"URL for '{selected_channel}' copied to clipboard.")
  222.         else:
  223.             messagebox.showerror("Error", "No valid channel selected to copy URL.")
  224.  
  225.     def mute_unmute(self):
  226.         global is_muted
  227.         is_muted = not is_muted
  228.         player.audio_toggle_mute()
  229.         self.mute_button.config(text="Unmute" if is_muted else "Mute")
  230.  
  231.     def set_volume(self, value):
  232.         player.audio_set_volume(int(float(value)))
  233.  
  234.     def capture_video(self):
  235.         try:
  236.             selected_channel = self.result_text.get(tk.ACTIVE).strip()
  237.             if selected_channel in self.channels_info:
  238.                 url = self.channels_info[selected_channel]
  239.                 filename = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[("MP4 files", "*.mp4")])
  240.                 if filename:
  241.                     command = [FFMPEG_PATH, '-y', '-i', url, '-t', '03:55:00', '-c', 'copy', filename]
  242.                     threading.Thread(target=lambda: subprocess.run(command)).start()
  243.                     messagebox.showinfo("Capturing", f"Capturing 03:55 minutes of video to {filename}")
  244.             else:
  245.                 messagebox.showerror("Error", "Selected text is not a valid URL.")
  246.         except tk.TclError:
  247.             messagebox.showerror("Error", "No text selected.")
  248.  
  249.     def record_audio(self):
  250.         try:
  251.             selected_channel = self.result_text.get(tk.ACTIVE).strip()
  252.             if selected_channel in self.channels_info:
  253.                 url = self.channels_info[selected_channel]
  254.                 filename = filedialog.asksaveasfilename(defaultextension=".mp3", filetypes=[("MP3 files", "*.mp3")])
  255.                 if filename:
  256.                     command = [FFMPEG_PATH, '-y', '-i', url, '-f', 'mp3', '-c:a', 'libmp3lame', filename]
  257.                     self.process = subprocess.Popen(command)
  258.                     messagebox.showinfo("Recording", f"Recording audio to {filename}")
  259.             else:
  260.                 messagebox.showerror("Error", "Selected text is not a valid URL.")
  261.         except tk.TclError:
  262.             messagebox.showerror("Error", "No text selected.")
  263.  
  264.     def stop_recording(self):
  265.         if self.process:
  266.             self.process.terminate()
  267.             self.process = None
  268.             messagebox.showinfo("Stopped", "Recording stopped")
  269.  
  270.     def capture_screenshots(self):
  271.         selected_channel = self.result_text.get(tk.ACTIVE).strip()
  272.         if selected_channel in self.channels_info:
  273.             url = self.channels_info[selected_channel]
  274.             filename_base = filedialog.asksaveasfilename(defaultextension=".png", filetypes=[("PNG files", "*.png")])
  275.             if filename_base:
  276.                 self.capture_screenshots_recursively(url, filename_base, 10, 2, 0)
  277.         else:
  278.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  279.  
  280.     def capture_screenshots_recursively(self, url, filename_base, total_screenshots, interval, count):
  281.         if count < total_screenshots:
  282.             filename = f"{filename_base}_{count + 1}.png"
  283.             player.video_take_snapshot(0, filename, 0, 0)
  284.             self.after(interval * 1000, self.capture_screenshots_recursively, url, filename_base, total_screenshots, interval, count + 1)
  285.         else:
  286.             messagebox.showinfo("Capturing Screenshots", f"Captured {total_screenshots} screenshots every {interval} seconds to {filename_base}")
  287.  
  288.     def toggle_fullscreen(self):
  289.         self.is_fullscreen = not self.is_fullscreen
  290.         self.attributes("-fullscreen", self.is_fullscreen)
  291.         self.control_frame.pack_forget() if self.is_fullscreen else self.control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  292.         self.additional_buttons_frame.pack_forget() if self.is_fullscreen else self.additional_buttons_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  293.         self.result_frame.pack_forget() if self.is_fullscreen else self.result_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=1, pady=5)
  294.  
  295.     def show_controls_on_mouse_move(self, event):
  296.         if self.is_fullscreen:
  297.             self.control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  298.             self.additional_buttons_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
  299.             self.result_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=1, pady=5)
  300.             self.after(2000, self.hide_controls)
  301.  
  302.     def hide_controls(self):
  303.         if self.is_fullscreen:
  304.             self.control_frame.pack_forget()
  305.             self.additional_buttons_frame.pack_forget()
  306.             self.result_frame.pack_forget()
  307.  
  308.     def download_video(self):
  309.         selected_channel = self.result_text.get(tk.ACTIVE).strip()
  310.         if selected_channel in self.channels_info:
  311.             url = self.channels_info[selected_channel]
  312.             filename = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[("MP4 files", "*.mp4")])
  313.             if filename:
  314.                 command = [WGET_PATH, url, "-O", filename]
  315.                 threading.Thread(target=lambda: subprocess.run(command)).start()
  316.                 messagebox.showinfo("Downloading", f"Downloading video to {filename}")
  317.         else:
  318.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  319.  
  320.     def download_with_ffmpeg(self):
  321.         selected_channel = self.result_text.get(tk.ACTIVE).strip()
  322.         if selected_channel in self.channels_info:
  323.             url = self.channels_info[selected_channel]
  324.             filename = filedialog.asksaveasfilename(defaultextension=".mp4", filetypes=[("MP4 files", "*.mp4")])
  325.             if filename:
  326.                 command = [FFMPEG_PATH, '-y', '-i', url, '-c', 'copy', filename]
  327.                 print(f"Running command: {' '.join(command)}")  # Print the command for debugging
  328.                 try:
  329.                     threading.Thread(target=lambda: subprocess.run(command)).start()
  330.                     messagebox.showinfo("Downloading", f"Downloading video with ffmpeg to {filename}")
  331.                 except Exception as e:
  332.                     messagebox.showerror("Error", f"Failed to start download: {str(e)}")
  333.         else:
  334.             messagebox.showerror("Error", "Selected text is not a valid URL.")
  335.  
  336. if __name__ == "__main__":
  337.     app = NajeebChannelPlayer()
  338.     app.mainloop()
  339.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement