main.py
an anonymous user
·
Python
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
Embed on website
To embed this program on your website, copy the following code and paste it into your website's HTML:
Comments
This comment belongs to a banned user and is only visible to admins.
This comment belongs to a deleted user and is only visible to admins.