Привет, Хабр! В этой статье я хочу поделиться опытом разработки самого популярного загрузчика видео в RuStore и рассказать, как я использовал потрясающую библиотеку для интеграции Python кода в свой проект.
К моему удивлению, я не нашел ни одного русскоязычного материала про Chaquopy, о котором сегодня пойдет речь.
Chaquopy — это библиотека, которая предоставляет всё необходимое для использования компонентов Python в Android приложение, включая:
Полную интеграцию со стандартной системой сборки Gradle в Android Studio.
Простые API для вызова Python-кода из Java/Kotlin и наоборот.
Широкий спектр сторонних пакетов Python, включая SciPy, OpenCV, TensorFlow и многое другое.
Примеры приложений, использующих Chaquopy, включают Electron Cash и SummaryYou
Предыстория
В начале 2023 года я начал разработку своего загрузчика видео для Android.
За основу была взята библиотека yt-dlp, которая является швейцарским ножом в мире скачивания видео и используется практически всеми онлайн-загрузчиками.
Эта библиотека поддерживает более тысячи ресурсов.
Самой большой проблемой оказалось найти работающую обертку на Java/Kotlin, реализующую весь функционал данной библиотеки. Спойлер: я её так и не нашел.
Но благодаря Chaquopy мне удалось интегрировать yt-dlp в свой проект, и это чертовски круто!
Забегая немного вперед, уточню, что были попытки перенести всю логику скачивания на сервер. Мне удалось реализовать склеивание видео и аудиодорожки для YouTube, что позволило пользователям скачивать видео в высоком качестве 1080p и выше.
Однако однажды подписчик решил потроллить меня, скачивая 24-часовые видео журчания Ниагарского водопада в 4K. У этого парня определенно есть чувство юмора:)
Тогда мне стало ясно, почему у многих онлайн-загрузчиков видео с YouTube нет функции выбора такого высокого качества, а лишь разрешения 360-720p.
Как говорится, если на стене висит ружьё, оно обязательно выстрелит.
Вдобавок к этому, YouTube очень быстро ввел лимиты на наш IP, из-за чего при скачивании возникали ошибки.
Было принято решение вернуться к клиентской обработке и скачиванию видео.
Как оказалось, современные смартфоны на Android довольно шустро справляются со склеиванием видео в высоком качестве. Да и как известно, лучшее — враг хорошего.
Начинаем работу с Chaquopy
В первой части мы подключим библиотеку и напишем простой Hello World, а во второй части я продемонстрирую пример использования библиотеки в своем рабочем проекте.
Весь код базового проекта я выложил на GitFlic.
// build.gradle.kts (Project:ChaquopyHelloWorld)
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.jetbrainsKotlinAndroid) apply false
id("com.chaquo.python") version "15.0.1" apply false
}
// build.gradle.kts (Module:app)
plugins {
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsKotlinAndroid)
id("com.chaquo.python")
}
android {
defaultConfig {
ndk {
abiFilters += listOf("x86", "x86_64", "armeabi-v7a", "arm64-v8a")
}
}
//// ....
}
chaquopy {
defaultConfig {
pip {
// Здесь подключаем библиотеки, например yt-dlp
// install("yt-dlp")
}
}
}
dependencies {
///....
}
Вот так выглядит весь код для подключения Chaquopy.
Стоит отметить, что необходимо указать abiFilters для поддержки всех архитектур процессора.
В блоке конфигурации Pip мы можем указать Python библиотеки, которые хотим подключить.
После установки зависимостей в файловой структуре проекта появится папка python. Именно туда мы и будем писать наш Python-код.
Давайте напишим простейшую hello world функцию:
#helloworld.py
def get_text(name : str):
return "Привет, " + name
Инициализируем Chaquopy в onCreate Application класса и вызываем в MainActivity функцию get_text в для получения строчки и отображаем её на экране:
class App : Application() {
override fun onCreate() {
super.onCreate()
if (!Python.isStarted()) {
Python.start(AndroidPlatform(this))
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val python = Python.getInstance()
val helloText = python.getModule("helloworld")
.callAttr("get_text", "Хабр").toString()
setContent {
ChaquopyHelloWorldTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Text(text = helloText)
}
}
}
}
}
Усложняем
Теперь давайте перейдем к конкретному кейсу использования библиотеки в продакшн-проекте для загрузки видео с YouTube в высоком качестве 1080p+.
Кратко пробежимся по коду: я передаю в метод download ссылку на видео, формат видео (в yt-dlp это называется идентификатор качества), путь для сохранения (локальная папка приложения) и расширение конечного файла.
Сначала скачиваются аудио- и видеодорожки, затем с помощью FFmpegKit они склеиваются в единый видеофайл, а исходники удаляются.
Кстати, как вы могли заметить, Kotlin и Python код можно смешивать в одном файле.
val pythonFile = python.getModule("download_hq_youtube_vid")
pythonFile.callAttr(
"download",
url,
path,
filename,
format,
ext
)
import os
import yt_dlp
from com.arthenica.ffmpegkit import FFmpegKit
def download(url: str, path: str, title: str, format: str, ext: str):
os.chdir(path)
audio_filename = title + "_audio.webm"
video_filename = title + "_video." + ext
hq_options = {
'format': format,
'outtmpl': video_filename
}
yt_dlp.YoutubeDL(hq_options).download([url])
video_output = title + "." + ext
audio_options = {
'format': 'bestaudio',
'outtmpl': audio_filename
}
yt_dlp.YoutubeDL(audio_options).download([url])
command = "-i " + video_filename + " -i " + audio_filename + " -c:v copy -c:a copy " + video_output
FFmpegKit.execute(command)
os.remove(audio_filename)
os.remove(video_filename)
Надеюсь, что статья была вам полезной. Спасибо за внимание!
Zrgk
yt-dlp так-то из termux прекрасно работает