The Swiss-army knife for embeddable media on Android.
Convert videos and GIFs to platform-ready animated WebP, compress images to WebP/JPEG/PNG/AVIF, inspect Open Graph and social embed metadata, and upload files to anonymous hosts — all from one app with a clean Material 3 dark-mode UI.
Every push to main triggers a CI build that produces split-ABI APKs:
| ABI | Best for |
|---|---|
arm64-v8a |
Modern phones (Pixel, Samsung Galaxy S/A series, OnePlus) |
armeabi-v7a |
Older 32-bit ARM devices |
x86_64 |
Emulators, Chromebooks |
universal |
Any device (larger download) |
- Adaptive quality algorithm — starts at target quality, steps down until file fits the size limit
- Platform presets with tuned parameters:
- Discord — 10 MB / 720p / 12 fps
- Telegram — 256 KB / 512px / 30 fps (sticker-ready)
- Slack — 5 MB / 640px / 12 fps
- Custom — full manual control
- Lanczos downscaling, optional text sharpening (
unsharpfilter) - Real-time progress with quality-step feedback
- Share/Save output directly from the result card
- Accepts shared media via Android intent filters
- Fetches and parses Open Graph, Twitter Card, and general
<meta>tags - Discord/Slack-style live embed preview card
- Expandable tag sections with one-tap copy
- Extracts favicon, canonical URL, charset, theme-color, robots, generator
- Powered by Jsoup for robust HTML parsing
- Upload to 0x0.st (512 MB) or catbox.moe (200 MB)
- EXIF stripping — removes GPS, camera info, artist, serial numbers before upload
- Determinate progress bar with chunked streaming (no full-file memory buffering)
- Copy URL or share result instantly
- Output formats: WebP, JPEG, PNG, AVIF
- AVIF encoding via avif-coder (libaom, speed 6 — Squoosh.app equivalent)
- Quality slider (1–100) for lossy formats
- Lossless mode for WebP and AVIF
- Max dimension scaling with efficient
inSampleSizesubsampling - Before/after size comparison with savings percentage
- Image preview of compressed output
app.embeddy
├── conversion/ # FFmpeg-kit animated WebP pipeline
│ ├── ConversionEngine # Adaptive quality loop with callbackFlow
│ ├── ConversionConfig # Mutable settings from presets
│ └── Preset # Discord, Telegram, Slack, Custom
├── inspect/
│ └── MetadataEngine # Jsoup-based OG/Twitter/meta parser
├── squoosh/
│ └── SquooshEngine # Bitmap.compress + HeifCoder AVIF
├── upload/
│ └── UploadEngine # Multipart POST with ProgressOutputStream
├── viewmodel/ # AndroidViewModel per tab
├── navigation/
│ ├── EmbeddyTab # Tab enum with Material icons
│ └── AppScaffold # Scaffold + NavigationBar + AnimatedContent
└── ui/
├── screens/ # ConvertScreen, InspectScreen, UploadScreen, SquooshScreen
├── components/ # MediaPicker, SettingsPanel, ConversionProgress, OutputPreview
└── theme/ # Material 3 dark theme
| Component | Library |
|---|---|
| UI | Jetpack Compose + Material 3 |
| Video → WebP | FFmpeg-kit (libwebp_anim) |
| AVIF encoding | avif-coder (libaom via JNI) |
| Image loading | Coil (compose, gif, video) |
| HTML parsing | Jsoup |
| EXIF handling | AndroidX ExifInterface |
| Navigation | Tab-based with AnimatedContent |
| Async | Kotlin Coroutines + StateFlow |
- JDK 17+
- Android SDK with
compileSdk 35
./gradlew assembleDebugA helper script handles the aapt2 override needed for on-device builds:
bash build-and-install.sh # build debug
bash build-and-install.sh --install # build + install via adb
bash build-and-install.sh --release # build releaseThe build produces per-ABI APKs (arm64-v8a, armeabi-v7a, x86_64) plus a universal APK. Configured in app/build.gradle.kts:
splits {
abi {
isEnable = true
include("arm64-v8a", "armeabi-v7a", "x86_64")
isUniversalApk = true
}
}Every push to main triggers the GitHub Actions workflow:
- Build release APKs (all ABIs)
- Rename with version:
Embeddy-v{major}.{minor}.{build}-{abi}.apk - Upload as build artifacts (30-day retention)
- Create a GitHub Release tagged
v{major}.{minor}.{build}with:- Auto-generated changelog from commit messages
- All APK variants attached
- Marked as
latest
Version is derived from version.properties (major/minor) + github.run_number (patch).
GPL-3.0 License — see LICENSE file for details.