import os import sys import urllib.parse import requests import time from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QListWidget, QSlider, QMessageBox, QTextEdit) from PyQt5.QtCore import Qt, QTimer import vlc import subprocess class VLCIPTVPlayer(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("VLC IPTV Player") self.resize(1024, 768) self.php_port = 8888 self.php_dir = os.path.join(os.path.dirname(__file__), "php_files") os.makedirs(self.php_dir, exist_ok=True) # Debug console self.debug_console = QTextEdit() self.debug_console.setReadOnly(True) # Initialize UI and VLC self.init_ui() self.init_vlc() # Download and process files self.download_and_process_files() def init_ui(self): """Initialize the user interface""" main_widget = QWidget(self) self.setCentralWidget(main_widget) layout = QVBoxLayout() main_widget.setLayout(layout) # Debug console layout.addWidget(self.debug_console, 1) # Video frame self.video_frame = QWidget() self.video_frame.setStyleSheet("background-color: black;") layout.addWidget(self.video_frame, 3) # Playlist self.playlist = QListWidget() self.playlist.itemDoubleClicked.connect(self.play_selected) layout.addWidget(self.playlist, 1) # Controls control_layout = QHBoxLayout() self.play_button = QPushButton("Play") self.play_button.clicked.connect(self.play_selected) self.stop_button = QPushButton("Stop") self.stop_button.clicked.connect(self.stop) self.reload_button = QPushButton("Update Files") self.reload_button.clicked.connect(self.download_and_process_files) self.volume_slider = QSlider(Qt.Horizontal) self.volume_slider.setRange(0, 100) self.volume_slider.setValue(50) self.volume_slider.valueChanged.connect(self.set_volume) control_layout.addWidget(self.play_button) control_layout.addWidget(self.stop_button) control_layout.addWidget(self.reload_button) control_layout.addWidget(QLabel("Volume:")) control_layout.addWidget(self.volume_slider) layout.addLayout(control_layout) def init_vlc(self): """Initialize VLC media player""" try: self.instance = vlc.Instance() self.media_player = self.instance.media_player_new() if sys.platform == "win32": self.media_player.set_hwnd(self.video_frame.winId()) else: self.media_player.set_xwindow(self.video_frame.winId()) self.log_message("VLC initialized successfully") except Exception as e: self.log_message(f"VLC initialization failed: {str(e)}", error=True) def log_message(self, message, error=False): """Add message to debug console""" timestamp = time.strftime("%H:%M:%S", time.localtime()) if error: self.debug_console.setTextColor(Qt.red) self.debug_console.append(f"[ERROR {timestamp}] {message}") else: self.debug_console.setTextColor(Qt.black) self.debug_console.append(f"[INFO {timestamp}] {message}") self.debug_console.setTextColor(Qt.black) self.debug_console.ensureCursorVisible() def download_and_process_files(self): """Download and process all required files without mixing them up""" files = { "myportal.php": "https://iptv.nywebforum.com/myportal.php?download=true", "mac_list.php": "https://iptv.nywebforum.com/mac_list.php?download=true", "playlist.m3u": "https://iptv.nywebforum.com/playlist.m3u" } for filename, url in files.items(): try: # Download to temporary file first temp_path = os.path.join(self.php_dir, f"temp_{filename}") final_path = os.path.join(self.php_dir, filename) response = requests.get(url, timeout=10) # Write to temporary file with open(temp_path, 'wb') as f: f.write(response.content) # Verify content is correct before replacing with open(temp_path, 'r', encoding='utf-8') as f: content = f.read() if filename == "myportal.php" and "Mac List File is OK" in content: raise Exception("Downloaded myportal.php contains mac_list.php content!") # Only replace original file if download is good if os.path.exists(final_path): os.remove(final_path) os.rename(temp_path, final_path) self.log_message(f"Successfully processed {filename}") except Exception as e: self.log_message(f"Failed to process {filename}: {str(e)}", error=True) # Keep old file if download fails if os.path.exists(temp_path): os.remove(temp_path) # Now process URL replacements self.process_url_replacements() self.load_playlist() def process_url_replacements(self): """Replace server URLs with localhost in all files""" try: # Process myportal.php myportal_path = os.path.join(self.php_dir, "myportal.php") if os.path.exists(myportal_path): with open(myportal_path, 'r', encoding='utf-8') as f: content = f.read() content = content.replace( "https://iptv.nywebforum.com", f"http://localhost:{self.php_port}" ) with open(myportal_path, 'w', encoding='utf-8') as f: f.write(content) # Process playlist.m3u playlist_path = os.path.join(self.php_dir, "playlist.m3u") if os.path.exists(playlist_path): with open(playlist_path, 'r', encoding='utf-8') as f: content = f.read() content = content.replace( "https://iptv.nywebforum.com", f"http://localhost:{self.php_port}" ) with open(playlist_path, 'w', encoding='utf-8') as f: f.write(content) self.log_message("URL replacements completed successfully") except Exception as e: self.log_message(f"Error during URL replacement: {str(e)}", error=True) def load_playlist(self): """Load the processed playlist""" playlist_path = os.path.join(self.php_dir, "playlist.m3u") if os.path.exists(playlist_path): try: with open(playlist_path, 'r', encoding='utf-8') as f: lines = f.readlines() self.playlist.clear() for line in lines: line = line.strip() if line and not line.startswith("#"): # Ensure all URLs point to local server line = line.replace( "https://iptv.nywebforum.com", f"http://localhost:{self.php_port}" ) self.playlist.addItem(line) self.log_message("Playlist loaded successfully") except Exception as e: self.log_message(f"Error loading playlist: {str(e)}", error=True) def play_selected(self): """Play the selected stream""" selected_items = self.playlist.selectedItems() if not selected_items: self.log_message("No stream selected", error=True) return stream_url = selected_items[0].text() self.log_message(f"Attempting to play: {stream_url}") try: # Execute PHP script locally if needed if "myportal.php" in stream_url: parsed = urllib.parse.urlparse(stream_url) params = urllib.parse.parse_qs(parsed.query) # Prepare environment variables env = os.environ.copy() for key, values in params.items(): if values: env[key.upper()] = values[0] # Execute PHP script php_script = os.path.join(self.php_dir, "myportal.php") result = subprocess.run( ["php", php_script], env=env, capture_output=True, text=True ) # Get the stream URL from output stream_url = result.stdout.strip() self.log_message(f"PHP script returned: {stream_url}") if not stream_url.startswith(("http://", "https://")): raise Exception(f"Invalid stream URL: {stream_url}") # Play the stream media = self.instance.media_new(stream_url) self.media_player.set_media(media) if self.media_player.play() == -1: raise Exception("VLC failed to start playback") self.log_message("Playback started successfully") except Exception as e: self.log_message(f"Playback error: {str(e)}", error=True) QMessageBox.critical(self, "Playback Error", f"Could not play stream:\n{str(e)}") def stop(self): """Stop playback""" self.media_player.stop() self.log_message("Playback stopped") def set_volume(self, value): """Set player volume""" self.media_player.audio_set_volume(value) self.log_message(f"Volume set to {value}%") def closeEvent(self, event): """Clean up when closing""" self.stop() super().closeEvent(event) if __name__ == "__main__": # Check dependencies try: import requests import vlc except ImportError as e: QMessageBox.critical(None, "Missing Dependencies", f"Required packages missing:\n{str(e)}\n" "Please install with: pip install python-vlc requests") sys.exit(1) # Check if PHP is available try: subprocess.run(["php", "-v"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) except: QMessageBox.critical(None, "PHP Not Found", "PHP is required but not found in system PATH.\n" "Please install PHP or place PHP binaries in the application directory.") sys.exit(1) app = QApplication(sys.argv) player = VLCIPTVPlayer() player.show() sys.exit(app.exec_())