Как использовать Python в нативном Android приложении. Мой опыт

от автора

Привет, Хабр! В этой статье я хочу поделиться опытом разработки самого популярного загрузчика видео в RuStore и рассказать, как я использовал потрясающую библиотеку для интеграции Python кода в свой проект.

Загрузчик видео доступен в RuStore

Загрузчик видео доступен в RuStore

К моему удивлению, я не нашел ни одного русскоязычного материала про Chaquopy, о котором сегодня пойдет речь.

Chaquopy — это библиотека, которая предоставляет всё необходимое для использования компонентов Python в Android приложение, включая:

  1. Полную интеграцию со стандартной системой сборки Gradle в Android Studio.

  2. Простые API для вызова Python-кода из Java/Kotlin и наоборот.

  3. Широкий спектр сторонних пакетов 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)

Надеюсь, что статья была вам полезной. Спасибо за внимание!


ссылка на оригинал статьи https://habr.com/ru/articles/815413/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *