Прога для скачки видео с вк по ссылке, забирайте ;-) Если надо могу доработать
Решил поделиться с вами простым кодом для скачки видео с вк без авторизации на сайте по ссылке (только открытое видео).
Могу по-быстрому накидать также для скачки музыки, видосов с ок.ру, или любого другого сайта)) Можно даже комбайн сделать - все в одном)
#!/usr/bin/env python3
"""
GUI для скачивания видео из ВКонтакте
Использует yt-dlp для загрузки видео
"""
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import threading
import os
import sys
from pathlib import Path
class VKVideoDownloader:
"""GUI приложение для скачивания видео из ВКонтакте"""
def __init__(self, root):
self.root = root
self.root.title("VK Video Downloader")
self.root.geometry("650x550")
self.root.resizable(True, True)
# Переменные
self.video_url = tk.StringVar()
self.download_path = tk.StringVar(value=os.path.expanduser("~/Downloads"))
# Флаг загрузки
self.is_downloading = False
self.setup_gui()
def setup_gui(self):
"""Настройка графического интерфейса"""
# Основной контейнер
main_frame = ttk.Frame(self.root, padding="15")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# Настройка растягивания
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
main_frame.rowconfigure(5, weight=1)
# Заголовок
title_label = ttk.Label(
main_frame,
text="🎬 VK Video Downloader",
font=("Segoe UI", 18, "bold")
)
title_label.grid(row=0, column=0, pady=(0, 20))
# Поле ввода ссылки
url_label = ttk.Label(main_frame, text="Ссылка на видео:", font=("Segoe UI", 10))
url_label.grid(row=1, column=0, sticky=tk.W, pady=(0, 5))
url_frame = ttk.Frame(main_frame)
url_frame.grid(row=2, column=0, sticky=(tk.W, tk.E), pady=(0, 15))
url_frame.columnconfigure(0, weight=1)
self.url_entry = ttk.Entry(url_frame, textvariable=self.video_url, font=("Segoe UI", 10))
self.url_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 10))
self.url_entry.bind("<Control-v>", self._on_paste)
self.url_entry.bind("<Control-V>", self._on_paste)
paste_btn = ttk.Button(url_frame, text="Вставить", command=self._paste_from_clipboard, width=8)
paste_btn.grid(row=0, column=1)
# Выбор папки для сохранения
folder_label = ttk.Label(main_frame, text="Папка сохранения:", font=("Segoe UI", 10))
folder_label.grid(row=3, column=0, sticky=tk.W, pady=(10, 5))
folder_frame = ttk.Frame(main_frame)
folder_frame.grid(row=4, column=0, sticky=(tk.W, tk.E), pady=(0, 15))
folder_frame.columnconfigure(0, weight=1)
self.folder_entry = ttk.Entry(folder_frame, textvariable=self.download_path, font=("Segoe UI", 9))
self.folder_entry.grid(row=0, column=0, sticky=(tk.W, tk.E), padx=(0, 10))
browse_btn = ttk.Button(folder_frame, text="📁 Обзор...", command=self.browse_folder)
browse_btn.grid(row=0, column=1)
# Кнопка скачивания
self.download_btn = ttk.Button(
main_frame,
text="⬇️ Скачать видео (макс. качество)",
command=self.start_download,
style="Accent.TButton"
)
self.download_btn.grid(row=5, column=0, pady=(10, 15), sticky=(tk.W, tk.E))
# Прогресс бар
self.progress = ttk.Progressbar(main_frame, orient="horizontal", mode="determinate")
self.progress.grid(row=6, column=0, sticky=(tk.W, tk.E), pady=(10, 5))
# Статус
self.status_label = ttk.Label(main_frame, text="", font=("Segoe UI", 9))
self.status_label.grid(row=7, column=0, sticky=tk.W)
# Текстовое поле для логов
log_label = ttk.Label(main_frame, text="Лог:", font=("Segoe UI", 10))
log_label.grid(row=8, column=0, sticky=tk.W, pady=(15, 5))
self.log_text = tk.Text(main_frame, height=8, width=70, font=("Consolas", 9))
self.log_text.grid(row=9, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), pady=(0, 10))
# Скроллбар для логов
scrollbar = ttk.Scrollbar(main_frame, orient=tk.VERTICAL, command=self.log_text.yview)
scrollbar.grid(row=9, column=1, sticky=(tk.N, tk.S))
self.log_text.configure(yscrollcommand=scrollbar.set)
# Кнопка очистки логов
clear_btn = ttk.Button(main_frame, text="Очистить лог", command=self.clear_log)
clear_btn.grid(row=10, column=0, sticky=tk.E)
def _paste_from_clipboard(self):
"""Вставить из буфера обмена"""
try:
self.video_url.set(self.root.clipboard_get())
except tk.TclError:
pass
def _on_paste(self, event):
"""Обработка вставки"""
try:
self.url_entry.insert(tk.INSERT, self.url_entry.clipboard_get())
except tk.TclError:
pass
return "break"
def browse_folder(self):
"""Выбор папки для сохранения"""
folder_selected = filedialog.askdirectory(initialdir=self.download_path.get())
if folder_selected:
self.download_path.set(folder_selected)
def log(self, message: str):
"""Добавить сообщение в лог"""
self.log_text.insert(tk.END, message + "\n")
self.log_text.see(tk.END)
self.root.update_idletasks()
def clear_log(self):
"""Очистить лог"""
self.log_text.delete(1.0, tk.END)
def update_status(self, message: str):
"""Обновить статус"""
self.status_label.config(text=message)
def start_download(self):
"""Запустить загрузку"""
if self.is_downloading:
messagebox.showwarning("Предупреждение", "Загрузка уже выполняется!")
return
url = self.video_url.get().strip()
if not url:
messagebox.showerror("Ошибка", "Введите ссылку на видео!")
return
# Проверка URL
if "vk.com/video" not in url and "vk.com/clip" not in url:
messagebox.showwarning(
"Предупреждение",
"Ссылка может быть некорректной.\nОжидаемый формат: https://vk.com/video-XXXXXXX_XXXXXXXX"
)
self.is_downloading = True
self.download_btn.config(state="disabled", text="⏳ Загрузка...")
self.progress['value'] = 0
# Запуск в отдельном потоке
thread = threading.Thread(
target=self._download_worker,
args=(url, self.download_path.get()),
daemon=True
)
thread.start()
def _download_worker(self, url: str, output_path: str):
"""Рабочий поток для загрузки"""
try:
import yt_dlp
except ImportError:
self.root.after(0, lambda: messagebox.showerror(
"Ошибка",
"yt-dlp не установлен!\nУстановите: pip install yt-dlp"
))
self.root.after(0, self._reset_ui)
return
# Создаем папку если не существует
if output_path and not os.path.exists(output_path):
os.makedirs(output_path)
# Автовыбор лучшего качества с наибольшим разрешением
# VK использует раздельные потоки, поэтому выбираем лучший доступный формат
ydl_opts = {
'outtmpl': str(Path(output_path) / '%(title)s.%(ext)s'),
'format': 'bestvideo*+bestaudio/best',
'merge_output_format': 'mp4',
'progress_hooks': [self._progress_hook],
'quiet': True,
'no_warnings': True,
'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
}
self.root.after(0, lambda: self.log(f"🎬 URL: {url}"))
self.root.after(0, lambda: self.log(f"📁 Путь: {output_path}"))
self.root.after(0, lambda: self.log("📺 Качество: АВТО (максимальное)"))
self.root.after(0, lambda: self.log("-" * 50))
try:
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
# Получаем информацию о видео
self.root.after(0, lambda: self.log("⏳ Получение информации о видео..."))
info = ydl.extract_info(url, download=False)
self.root.after(0, lambda: self.log(f"📹 Название: {info.get('title', 'N/A')}"))
self.root.after(0, lambda: self.log(f"👤 Автор: {info.get('uploader', 'N/A')}"))
duration = info.get('duration')
if duration:
minutes = duration // 60
seconds = duration % 60
self.root.after(0, lambda: self.log(f"⏱️ Длительность: {minutes}:{seconds:02d}"))
self.root.after(0, lambda: self.log("-" * 50))
self.root.after(0, lambda: self.log("⬇️ Начало загрузки..."))
# Скачиваем
ydl.download([url])
self.root.after(0, lambda: self.log("=" * 50))
self.root.after(0, lambda: self.log("✅ Видео успешно скачано!"))
self.root.after(0, lambda: self.update_status("Готово!"))
self.root.after(0, lambda: messagebox.showinfo("Успех", "Видео успешно скачано!"))
except yt_dlp.utils.DownloadError as e:
error_msg = f"❌ Ошибка загрузки: {str(e)}"
self.root.after(0, lambda: self.log(error_msg))
self.root.after(0, lambda: self.log("\nВозможные причины:"))
self.root.after(0, lambda: self.log(" • Видео приватное (требуется авторизация)"))
self.root.after(0, lambda: self.log(" • Видео удалено или недоступно"))
self.root.after(0, lambda: self.log(" • Неверная ссылка"))
self.root.after(0, lambda: messagebox.showerror("Ошибка", f"Не удалось скачать видео:\n{str(e)}"))
self.root.after(0, lambda: self.update_status("Ошибка!"))
except Exception as e:
error_msg = f"❌ Произошла ошибка: {str(e)}"
self.root.after(0, lambda: self.log(error_msg))
self.root.after(0, lambda: messagebox.showerror("Ошибка", str(e)))
self.root.after(0, lambda: self.update_status("Ошибка!"))
finally:
self.root.after(0, self._reset_ui)
def _progress_hook(self, d: dict):
"""Хук для отображения прогресса"""
if d['status'] == 'downloading':
total = d.get('total_bytes') or d.get('total_bytes_estimate', 0)
downloaded = d.get('downloaded_bytes', 0)
if total > 0:
percent = (downloaded / total) * 100
speed = d.get('speed', 0)
self.root.after(0, lambda: self.progress.config(value=percent))
if speed:
speed_str = f"{speed / 1024 / 1024:.2f} MB/s"
else:
speed_str = "N/A"
self.root.after(0, lambda: self.update_status(f"⏳ Загрузка: {percent:.1f}% | {speed_str}"))
elif d['status'] == 'finished':
self.root.after(0, lambda: self.progress.config(value=100))
self.root.after(0, lambda: self.update_status("✅ Обработка..."))
self.root.after(0, lambda: self.log("✅ Загрузка завершена, обработка..."))
def _reset_ui(self):
"""Сброс UI после загрузки"""
self.is_downloading = False
self.download_btn.config(state="normal", text="⬇️ Скачать видео")
def main():
root = tk.Tk()
# Установка стиля
try:
import ttkbootstrap as ttkb
style = ttkb.Style(theme="cosmo")
except ImportError:
pass # Используем стандартный ttk
app = VKVideoDownloader(root)
root.mainloop()
if __name__ == "__main__":
main()





