import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import vlc
import subprocess
import threading
# Constants
CHANNELS_FOLDER = 'CHANNELS'
VLC_PATH = r"C:\Program Files\VideoLAN\VLC\vlc.exe"
WGET_PATH = r"C:\CMDER\APP\wget.exe" # Update this with the correct path to wget.exe
FFMPEG_PATH = r"C:\CMDER\APP\ffmpeg.exe" # Update this with the correct path to ffmpeg.exe
# Initialize VLC
instance = vlc.Instance('--verbose 2')
player = instance.media_player_new()
class NajeebChannelPlayer(tk.Tk):
def __init__(self):
super().__init__()
self.title("Najeeb IPTV Channel Player")
self.geometry("1000x600")
self.configure(bg='#2E2E2E')
self.channels_info = {}
self.process = None
self.is_fullscreen = False
self.is_dragging_slider = False # Initialize as an instance variable
self.is_muted = False
self.create_widgets()
self.load_channels_from_folder()
self.update_video_slider()
def create_widgets(self):
self.control_frame = ttk.Frame(self, style="TFrame")
self.control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
self.search_entry = ttk.Entry(self.control_frame, width=50)
self.search_entry.pack(side=tk.LEFT, padx=5, pady=5)
search_button = ttk.Button(self.control_frame, text="Search", command=self.search_channels)
search_button.pack(side=tk.LEFT, padx=5, pady=5)
filter_button = ttk.Button(self.control_frame, text="Filter", command=self.filter_channels)
filter_button.pack(side=tk.LEFT, padx=5, pady=5)
copy_button = ttk.Button(self.control_frame, text="Copy URL", command=self.copy_selected_url)
copy_button.pack(side=tk.LEFT, padx=5, pady=5)
preview_button = ttk.Button(self.control_frame, text="Preview", command=self.preview_selected_channel)
preview_button.pack(side=tk.LEFT, padx=5, pady=5)
stop_button = ttk.Button(self.control_frame, text="Stop Preview", command=self.stop_preview)
stop_button.pack(side=tk.LEFT, padx=5, pady=5)
# Volume and Mute Controls
volume_frame = ttk.Frame(self.control_frame, style="TFrame")
volume_frame.pack(side=tk.LEFT, padx=5, pady=5)
volume_label = ttk.Label(volume_frame, text="Volume")
volume_label.pack(side=tk.LEFT)
volume_slider = ttk.Scale(volume_frame, from_=0, to=100, orient=tk.HORIZONTAL, command=self.set_volume)
volume_slider.set(50) # Default volume
volume_slider.pack(side=tk.LEFT, padx=5)
self.mute_button = ttk.Button(volume_frame, text="Mute", command=self.mute_unmute)
self.mute_button.pack(side=tk.LEFT, padx=5)
# Additional Buttons
self.additional_buttons_frame = ttk.Frame(self, style="TFrame")
self.additional_buttons_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
capture_video_button = ttk.Button(self.additional_buttons_frame, text="Capture Video", command=self.capture_video)
capture_video_button.pack(side=tk.LEFT, padx=5, pady=5)
record_audio_button = ttk.Button(self.additional_buttons_frame, text="Record Audio", command=self.record_audio)
record_audio_button.pack(side=tk.LEFT, padx=5, pady=5)
stop_record_button = ttk.Button(self.additional_buttons_frame, text="Stop Recording", command=self.stop_recording)
stop_record_button.pack(side=tk.LEFT, padx=5, pady=5)
screenshot_button = ttk.Button(self.additional_buttons_frame, text="Capture Screenshots", command=self.capture_screenshots)
screenshot_button.pack(side=tk.LEFT, padx=5, pady=5)
fullscreen_button = ttk.Button(self.additional_buttons_frame, text="Full Screen", command=self.toggle_fullscreen)
fullscreen_button.pack(side=tk.LEFT, padx=5, pady=5)
download_button = ttk.Button(self.additional_buttons_frame, text="Download with wget", command=self.download_video)
download_button.pack(side=tk.LEFT, padx=5, pady=5)
download_ffmpeg_button = ttk.Button(self.additional_buttons_frame, text="Download with ffmpeg", command=self.download_with_ffmpeg)
download_ffmpeg_button.pack(side=tk.LEFT, padx=5, pady=5)
# Video control slider
self.video_slider = ttk.Scale(self, from_=0, to=1000, orient=tk.HORIZONTAL)
self.video_slider.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=5)
self.video_slider.bind("<ButtonPress-1>", self.slider_pressed)
self.video_slider.bind("<ButtonRelease-1>", self.slider_released)
self.result_frame = ttk.Frame(self, style="TFrame")
self.result_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=False, padx=1, pady=5)
self.result_text = tk.Listbox(self.result_frame, width=30, height=25, selectmode=tk.SINGLE, bg='#FFFFFF', fg='#000000')
self.result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=False)
# Add scrollbars
vsb = ttk.Scrollbar(self.result_frame, orient="vertical", command=self.result_text.yview)
vsb.pack(side=tk.RIGHT, fill="y")
self.result_text.configure(yscrollcommand=vsb.set)
self.result_text.bind('<Double-1>', self.play_selected_channel)
self.video_frame = tk.Frame(self, bg='#000000')
self.video_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=10, pady=5)
self.video_panel = tk.Frame(self.video_frame, bg='#000000')
self.video_panel.pack(fill=tk.BOTH, expand=True)
# Ensure control frames are always visible
self.control_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
self.additional_buttons_frame.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)
def load_channels_from_folder(self):
try:
files = [f for f in os.listdir(CHANNELS_FOLDER) if f.endswith('.txt')]
all_channels = []
for file in files:
file_path = os.path.join(CHANNELS_FOLDER, file)
with open(file_path, 'r', encoding='utf-8') as f:
all_channels.extend(f.readlines())
self.process_text_data(all_channels)
except FileNotFoundError:
messagebox.showerror("Error", f"The folder '{CHANNELS_FOLDER}' does not exist.")
except PermissionError:
messagebox.showerror("Error", f"Permission denied while accessing '{CHANNELS_FOLDER}'.")
except Exception as e:
self.result_text.insert(tk.END, f"Error loading channels from folder: {str(e)}\n")
def process_text_data(self, text_data):
self.result_text.delete(0, tk.END)
self.channels_info = {}
for line in text_data:
line = line.strip()
if line:
if "http" in line:
# Find the URL by splitting on space
parts = line.split(' ', 1)
if len(parts) == 2:
channel_name = parts[0].strip()
url = parts[1].strip()
self.channels_info[channel_name] = url
self.result_text.insert(tk.END, channel_name)
def search_channels(self):
search_term = self.search_entry.get().lower()
self.result_text.delete(0, tk.END)
for channel_name, url in self.channels_info.items():
if search_term in channel_name.lower():
self.result_text.insert(tk.END, channel_name)
def filter_channels(self):
search_term = self.search_entry.get().lower()
self.result_text.delete(0, tk.END)
for channel_name, url in self.channels_info.items():
if search_term in channel_name.lower() or search_term in url.lower():
self.result_text.insert(tk.END, channel_name)
def play_selected_channel(self, event):
try:
selected_channel = self.result_text.get(tk.ACTIVE)
if selected_channel in self.channels_info:
url = self.channels_info[selected_channel]
subprocess.Popen([VLC_PATH, url])
except (tk.TclError, KeyError):
pass
def preview_selected_channel(self):
try:
selected_channel = self.result_text.get(tk.ACTIVE)
if selected_channel in self.channels_info:
url = self.channels_info[selected_channel]
self.play_vlc_stream(url)
except (tk.TclError, KeyError):
pass
def play_vlc_stream(self, stream_url):
media = instance.media_new(stream_url)
player.set_media(media)
player.set_hwnd(self.video_panel.winfo_id())
player.play()
def slider_pressed(self, event):
self.is_dragging_slider = True
def slider_released(self, event):
self.is_dragging_slider = False
value = self.video_slider.get()
self.set_position(value)
def set_position(self, value):
player.set_time(int((value / 1000) * player.get_length()))
def update_video_slider(self):
if player and not self.is_dragging_slider:
length = player.get_length()
time = player.get_time()
if length > 0:
value = int((time / length) * 1000)
self.video_slider.set(value)
self.after(1000, self.update_video_slider)
def set_volume(self, value):
player.audio_set_volume(int(float(value))) # Convert float to int
def mute_unmute(self):
if self.is_muted:
player.audio_set_mute(False)
self.mute_button.config(text="Mute")
else:
player.audio_set_mute(True)
self.mute_button.config(text="Unmute")
self.is_muted = not self.is_muted
def capture_video(self):
self.process = subprocess.Popen(['ffmpeg', '-f', 'gdigrab', '-framerate', '30', '-i', 'desktop', 'output.mp4'])
def record_audio(self):
self.process = subprocess.Popen(['ffmpeg', '-f', 'dshow', '-i', 'audio=Stereo Mix (Realtek(R) Audio)', 'output_audio.mp3'])
def stop_recording(self):
if self.process:
self.process.terminate()
self.process = None
def capture_screenshots(self):
subprocess.Popen(['ffmpeg', '-f', 'gdigrab', '-framerate', '1', '-i', 'desktop', '-frames:v', '1', 'screenshot.png'])
def copy_selected_url(self):
selected_channel = self.result_text.get(tk.ACTIVE)
if selected_channel in self.channels_info:
url = self.channels_info[selected_channel]
self.clipboard_clear()
self.clipboard_append(url)
def toggle_fullscreen(self):
self.is_fullscreen = not self.is_fullscreen
self.attributes("-fullscreen", self.is_fullscreen)
def stop_preview(self):
player.stop()
def download_video(self):
url = self.search_entry.get()
if url:
subprocess.Popen([WGET_PATH, url])
def download_with_ffmpeg(self):
url = self.search_entry.get()
if url:
subprocess.Popen([FFMPEG_PATH, '-i', url, 'output_video.mp4'])
if __name__ == "__main__":
app = NajeebChannelPlayer()
app.mainloop()