CNN TürkFenerbahçe Tarfin, Olympiakos’u deplasmanda mağlup ettiPunchAlonso sees Courtois qualities in Chelsea’s young goalkeeper PendersInquirerFewer Filipinos trust the news. Can PH media win them back?Bollywood HungamaSCOOP: Ranbir Kapoor SECRETLY tipped off Sandeep Reddy Vanga about Ramayana 2's delay; helped Prabhas' Spirit grab Diwali 2027!The Jerusalem PostMarco Rubio calls on Cubans to partner with CIA as Trump promises to 'take care of Cuba'ZDF heuteEntdecken Sie das ZDF-NachrichtenstudioThe South AfricanProteas suffer key injury blow ahead of Newlands Test deciderFotogramasViggo Mortensen, sobre su encuentro con Woody Allen: "Entré a una habitación y, efectivamente, allí estaba él, sentado detrás de un escritorio, sin decirme una palabra"The Sydney Morning HeraldFederal MP Helen Haines' condition improves for first time since attackHong Kong Free PressChina-funded Confucius Institutes deemed US national security threat: HegsethHet Laatste Nieuws“Coach in eerste klasse? Dat had ook hij niet zien aankomen”: de opmars van AA Gent-trainer Rik De Mil door de ogen van z’n twee boezemvriendenIl Fatto QuotidianoGermania, brucia il “Nido dell’Aquila” di Adolf Hitler: fermato un sospetto
The Daily Newsstand · Free, Always
Saturday, October 24, 2026

«Качалка видео для Windows и Mac: почему TikTok не пускал собранную программу, а QuickTime принимал видео за музыку»

Translate

Вставляешь ссылку на видео с YouTube, TikTok, VK или Instagram, выбираешь 1080 p, 720 p или 480 p и жмёшь «Скачать». Через несколько секунд на Рабочем столе лежит mp4, который открывается в QuickTime, на айфоне и в любом плеере Windows. Пока идёт загрузка, по пиксельному офису бегает человечек и складывает в папку листки.

Это Качалка — бесплатная программа с открытым кодом. Никаких аккаунтов, рекламы и водяных знаков. Ниже — из чего она собрана и два бага, на которые я потратил больше всего времени: оба проявлялись только в собранной программе и ни разу при запуске из кода.

Давно хотел делать бесплатно для людей, время пришло.

Из чего собрано

  • yt‑dlp делает всю тяжёлую работу: достаёт видео с сотен сайтов.

  • FFmpeg склеивает видео со звуком. Он едет внутри программы через пакет imageio-ffmpeg, так что ставить ничего не нужно.

  • CustomTkinter рисует окно: тёмная тема, фиолетовые кнопки.

  • PyInstaller собирает Kachalka.exe для Windows и Kachalka.app для Mac.

  • GitHub Actions собирает обе версии по тегу. У меня нет компьютера с Windows, так что exe я ни разу не собирал сам.

«Код писал вместе с Claude Code; идея, решения и проверка — мои».

Почему H.264, а не «лучшее качество»

Первое желание — качать максимум. Но YouTube отдаёт высокие разрешения в VP9 и AV1, а QuickTime и айфон такие файлы часто не открывают. Пользователь скачал видео, кликнул — а оно не играет. Поэтому Качалка всегда просит H.264 и звук AAC:

"format": "bv*+ba/b",
"format_sort": ["vcodec:h264", f"res:{height}", "acodec:m4a"],
"merge_output_format": "mp4",

Тонкость с res: yt‑dlp считает разрешение по меньшей стороне. Поэтому вертикальный TikTok 1080×1920 честно считается 1080 p и не отсекается фильтром «не больше 1080». Если бы я фильтровал по height, вертикальные видео скачивались бы в плохом качестве.

Цена решения — нет 4K: в H.264 его практически никто не отдаёт. Перекодировать 4K на компьютере пользователя — минуты ожидания, для простой качалки это лишнее.

Баг 1: TikTok пускает Python, но не пускает собранную программу

Из кода всё качалось. Собранная программа на той же ссылке падала:

ERROR: [TikTok] 7698495498537143604: Unexpected response from webpage request

Я последовательно исключал причины:

  • Сеть и VPN. VPN работает на весь компьютер, системного прокси нет. И скрипт, и программа ходят в сеть одинаково.

  • Окружение. Программа, запущенная из терминала, а не из Finder, падала так же.

  • Версия yt‑dlp. В логе сборки GitHub та же версия, что у меня, 2026.08.19.

  • Состав библиотек. Почти совпадал.

Остался Python. Локально у меня одна сборка Python, на GitHub — другая, с другими настройками TLS. По всей видимости, TikTok смотрит на «почерк» TLS‑соединения и одной сборке отдаёт нормальную страницу, а другой — заглушку. yt‑dlp, кстати, сам об этом предупреждал, а я не обратил внимания:

WARNING: [TikTok] The extractor is attempting impersonation,
but no impersonate target is available.

Решение — пакет curl_cffi: он умеет подключаться с отпечатком настоящего Chrome или Safari. Достаточно поставить yt‑dlp с нужным дополнением и не забыть положить пакет в сборку:

# requirements.txt
yt-dlp[default,curl-cffi]

# build.py
"--collect-all=curl_cffi",

Главный урок: проверять надо собранную программу, а не код. Локально ошибка не воспроизводилась ни разу. Я собрал пробную версию в отдельной ветке, скачал её из GitHub Actions и только после этого выпустил исправление.

Баг 2: видео из TikTok открывается как музыка

TikTok начал качаться, но в Finder вместо превью у файла была нота, а QuickTime видел в нём только звук. При этом ffprobe показывал нормальный H.264 1080×1080, а ffmpeg декодировал кадры без единой ошибки.

Странным было одно поле — масштаб времени видеодорожки:

stream|codec_type=video|time_base=1/5995319

Почти шесть миллионов делений в секунду. Я спросил у видеодвижка macOS напрямую, что он видит в файле:

asset = AVFoundation.AVURLAsset.URLAssetWithURL_options_(url, None)
len(asset.tracksWithMediaType_(AVFoundation.AVMediaTypeVideo))
# исходный файл — 0 видеодорожек
# после переупаковки — 1

Ноль. Для macOS видео в этом файле просто не существовало. Лечится переупаковкой без перекодирования: качество то же, работы на пару секунд.

ffmpeg -i in.mp4 -map 0 -c copy -video_track_timescale 90000 -movflags +faststart out.mp4

Теперь Качалка делает это после каждой загрузки. На Windows ffmpeg запускается с флагом CREATE_NO_WINDOW, иначе на секунду мелькает чёрное окно консоли.

Плавный прогресс, когда файлов два

YouTube отдаёт видео и звук отдельно, и прогресс yt‑dlp идёт дважды от 0 до 100%. Пользователь видит, как полоска доходит до конца и прыгает в ноль. Поэтому перед загрузкой Качалка смотрит размеры обеих частей и считает общий прогресс с весами. Полоска не прыгает к цели, а плавно догоняет её — каждые 16 мс проходит 12% оставшегося пути. Последние 3% оставлены на склейку.

Человечек в офисе

Гифка нарисована кодом на Pillow, без готовых ассетов. Холст 160×80 «пикселей» увеличивается в три раза без сглаживания. Офис — это кусок шириной 96 пикселей, который едет на 2 пикселя за кадр: за 48 кадров он проезжает ровно свою ширину, поэтому петля бесшовная. 48 кадров по 40 мс дают 25 кадров в секунду.

Ещё одна мелочь для Retina: CustomTkinter сам масштабирует картинки и размывает пиксель‑арт. Поэтому кадры заранее увеличиваются в два раза «по пикселям», и масштабировать окну уже нечего.

Сборка для двух систем без Windows

Одна матрица GitHub Actions: windows-latest собирает однофайловый exe, macos-latest — .app в zip. По тегу v* оба файла уходят в релиз, а к релизу прикладывается подпись происхождения. Любой может проверить, что файл собран из этого репозитория:

gh attestation verify Kachalka-Windows.exe --owner kozliq

Две вещи, которые пришлось объяснять в README:

  • Программа без платной подписи. Windows показывает «Система Windows защитила ваш компьютер», macOS — «не удаётся проверить разработчика». Это обходится за один шаг, но предупредить нужно.

  • Блокировки. Многие обходят их VPN‑расширением или DNS в настройках браузера. Программа настроек браузера не видит, и YouTube для неё недоступен. Поэтому сырые ошибки yt‑dlp переводятся на человеческий язык: вместо getaddrinfo failed Качалка пишет «Нет связи с сайтом — похоже, он заблокирован у провайдера» и советует включить VPN для всего компьютера.

Что дальше

В планах значок в строке меню Mac: нажал, вставил ссылку, скачал — без большого окна.

Код и готовые файлы для Windows и Mac: github.com/kozliq/kachalka

Если что‑то не качается — заведите issue со ссылкой, разберусь.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.