main.py

an anonymous user · January 17, 2026
import sys
import os
import threading
from datetime import datetime
from PyQt6.QtCore import QUrl, Qt, QPropertyAnimation, QPoint
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 
                             QLineEdit, QPushButton, QComboBox, QLabel, QFrame, 
                             QGraphicsOpacityEffect, QFileDialog, QMessageBox, QTextEdit)
from PyQt6.QtGui import QPixmap, QFont
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebEngineCore import QWebEngineProfile, QWebEngineUrlRequestInterceptor
import yt_dlp

class AdBlocker(QWebEngineUrlRequestInterceptor):
    def interceptRequest(self, info):
        url = info.requestUrl().toString()
        ad_keywords = [
            "googleads", "doubleclick", "adservice", "analytics", 
            "googlesyndication", "pixel.facebook", "adsystem", "marketing",
            "pagead", "stats.g.doubleclick.net"
        ]
        if any(keyword in url for keyword in ad_keywords):
            info.block(True)

class YTDownloader(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("YT Downloader Pro")
        self.resize(1200, 750)
        self.save_path = os.path.join(os.path.expanduser("~"), "Downloads")

        profile = QWebEngineProfile.defaultProfile()
        profile.setHttpCacheType(QWebEngineProfile.HttpCacheType.DiskHttpCache)
        
        default_font = QFont("sans-serif", 10)
        self.setFont(default_font)

        self.setStyleSheet("""
            QMainWindow { background-color: #ffffff; }
            QWidget {
                font-family: "Segoe UI", "Malgun Gothic", sans-serif;
                color: #000000;
            }
            QLineEdit, QComboBox, QLabel#PathDisplay { 
                border: 1px solid #cccccc; 
                border-radius: 8px; 
                padding: 0px 10px;
                background: #ffffff; 
                min-height: 32px; 
                max-height: 32px; 
                font-size: 12px;
            }
            QComboBox QAbstractItemView {
                border: 1px solid #cccccc;
                border-radius: 8px;
                background-color: #ffffff;
                selection-background-color: #f0f0f0;
                outline: 0px;
                padding: 5px;
            }
            QLineEdit:focus, QComboBox:focus {
                border: 1px solid #ff0000;
            }
            QFrame#Sidebar { border-left: 1px solid #eeeeee; background-color: #ffffff; }
            QComboBox::drop-down { border: 0px; width: 25px; }
            
            QPushButton { 
                border-radius: 8px; 
                font-weight: bold; 
                font-size: 12px;
                height: 32px;
            }
            QPushButton#DownloadBtn { 
                background-color: #ff0000; 
                color: #ffffff; 
                height: 45px; 
                font-size: 14px; 
                margin-top: 10px;
            }
            QPushButton#DownloadBtn:hover { background-color: #cc0000; }
            QTextEdit#LogView { 
                border: 1px solid #eeeeee; 
                border-radius: 8px; 
                background-color: #fdfdfd; 
                font-family: "Consolas", "Courier New", monospace;
                font-size: 11px; 
            }
            QLabel#SectionTitle { 
                font-weight: bold; 
                font-size: 11px; 
                color: #666666;
                margin-top: 5px;
            }
        """)

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)

        self.url_bar = QLineEdit()
        self.url_bar.setPlaceholderText("Enter URL or search...")
        self.url_bar.returnPressed.connect(self.navigate_to_url)
        main_layout.addWidget(self.url_bar)

        content_layout = QHBoxLayout()
        self.browser = QWebEngineView()
        interceptor = AdBlocker()
        QWebEngineProfile.defaultProfile().setUrlRequestInterceptor(interceptor)
        self.browser.setUrl(QUrl("https://[Log in to view URL]"))
        self.browser.urlChanged.connect(lambda q: self.url_bar.setText(q.toString()))
        self.browser.loadFinished.connect(self.apply_auto_skip)
        content_layout.addWidget(self.browser, stretch=1)

        sidebar = QFrame()
        sidebar.setObjectName("Sidebar")
        sidebar.setFixedWidth(240)
        side_layout = QVBoxLayout(sidebar)
        side_layout.setContentsMargins(15, 0, 5, 0)
        side_layout.setSpacing(10)

        side_layout.addWidget(self.create_title_label("Format"))
        self.type_combo = QComboBox()
        self.type_combo.addItems(["MP4 Video", "MP3 Audio"])
        self.type_combo.currentTextChanged.connect(self.update_quality_list)
        side_layout.addWidget(self.type_combo)

        side_layout.addWidget(self.create_title_label("Quality"))
        self.quality_combo = QComboBox()
        side_layout.addWidget(self.quality_combo)
        self.update_quality_list(self.type_combo.currentText())

        side_layout.addWidget(self.create_title_label("Download Path"))
        self.path_display = QLabel(self.get_short_path(self.save_path))
        self.path_display.setObjectName("PathDisplay")
        self.path_display.setCursor(Qt.CursorShape.PointingHandCursor)
        self.path_display.mousePressEvent = self.select_path
        side_layout.addWidget(self.path_display)

        self.download_btn = QPushButton("DOWNLOAD")
        self.download_btn.setObjectName("DownloadBtn")
        self.download_btn.clicked.connect(self.start_download_thread)
        side_layout.addWidget(self.download_btn)

        side_layout.addWidget(self.create_title_label("Download List"))
        self.log_view = QTextEdit()
        self.log_view.setObjectName("LogView")
        self.log_view.setReadOnly(True)
        side_layout.addWidget(self.log_view)

        content_layout.addWidget(sidebar)
        main_layout.addLayout(content_layout)

    def create_title_label(self, text):
        label = QLabel(text)
        label.setObjectName("SectionTitle")
        return label

    def get_short_path(self, path):
        if len(path) > 25:
            return "..." + path[-22:]
        return path

    def update_quality_list(self, text):
        self.quality_combo.clear()
        if "MP4" in text:
            self.quality_combo.addItems(["1080P", "720P", "480P", "360P"])
        else:
            self.quality_combo.addItems(["320Kbps", "256Kbps", "192Kbps", "128Kbps"])

    def select_path(self, event):
        path = QFileDialog.getExistingDirectory(self, "Select Save Folder")
        if path:
            self.save_path = path
            self.path_display.setText(self.get_short_path(path))

    def apply_auto_skip(self):
        js = """
        const clearAds = () => {
            const video = document.querySelector('video');
            const ad = document.querySelector('.ad-showing, .ad-interrupting');
            if (ad && video && isFinite(video.duration)) {
                video.currentTime = video.duration;
            }
            const skipButtons = ['.ytp-ad-skip-button', '.ytp-ad-skip-button-modern', '.ytp-ad-overlay-close-button'];
            skipButtons.forEach(cls => {
                const btn = document.querySelector(cls);
                if (btn) btn.click();
            });
            const style = document.createElement('style');
            style.innerHTML = `
                ytd-ad-slot-renderer, ytd-promoted-sparkles-renderer, 
                .ytd-player-legacy-ad-container, .ytp-ad-player-overlay { display: none !important; }
            `;
            if (!document.getElementById('ad-style-blocker')) {
                style.id = 'ad-style-blocker';
                document.head.appendChild(style);
            }
        };
        setInterval(clearAds, 300);
        """
        self.browser.page().runJavaScript(js)

    def navigate_to_url(self):
        url = self.url_bar.text()
        if not url.startswith("http"):
            url = f"https://[Log in to view URL]"
        self.browser.setUrl(QUrl(url))

    def add_log(self, message):
        self.log_view.append(f"[{datetime.now().strftime('%H:%M')}] {message}")

    def start_download_thread(self):
        url = self.browser.url().toString()
        if "watch?v=" not in url:
            QMessageBox.warning(self, "Notification", "Please go to a video page to download.")
            return
        self.add_log(f"Starting download...")
        threading.Thread(target=self.download_core, args=(url,), daemon=True).start()

    def download_core(self, url):
        fmt_type = self.type_combo.currentText()
        quality_label = self.quality_combo.currentText()
        numeric_quality = quality_label.replace("P", "").replace("Kbps", "")
        save_template = os.path.join(self.save_path, f"%(title)s_{quality_label}.%(ext)s")
        ydl_opts = {'outtmpl': save_template, 'quiet': True, 'noprogress': True}
        
        if "MP3" in fmt_type:
            ydl_opts.update({
                'format': 'bestaudio/best',
                'postprocessors': [{
                    'key': 'FFmpegExtractAudio',
                    'preferredcodec': 'mp3',
                    'preferredquality': numeric_quality
                }]
            })
        else:
            ydl_opts.update({
                'format': f'bestvideo[height<={numeric_quality}]+bestaudio/best/best',
                'merge_output_format': 'mp4'
            })
            
        try:
            with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                ydl.download([url])
                self.add_log(f"Success: {quality_label}")
        except Exception as e:
            self.add_log(f"Error: {str(e)}")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = YTDownloader()
    window.show()
    sys.exit(app.exec())
Output

Comments

Please sign up or log in to contribute to the discussion.