📱 Android App Architecture:
├── 🎯 Clean Architecture + MVVM
├── 🗃️ Room Database (for download history)
├── 🌐 Retrofit + OkHttp (for networking)
├── 💉 Hilt (Dependency Injection)
├── 🎨 Jetpack Compose (UI)
├── 🎵 MediaStore (for file storage)
├── 🔄 WorkManager (background downloads)
├── 📁 File System (actual file storage)
└── 🔐 BuildConfig (API keys management)
Let me create the complete project structure:
app/
├── src/main/
│ ├── java/dev/korryr/tubefetch/
│ │ ├── data/ # Data Layer
│ │ ├── domain/ # Domain Layer
│ │ ├── ui/ # Presentation Layer
│ │ ├── di/ # Dependency Injection
│ │ └── utils/ # Utilities
│ └── res/
├── build.gradle.kts
├── proguard-rules.pro
└── keys.properties # API keys (gitignored)
This project uses the YouTube Media Downloader API on RapidAPI as the backend for analyzing and downloading YouTube videos.
- File:
keys.properties(project root, gitignored) - Required keys:
YOUTUBE_API_KEY=...YOUTUBE_BASE_URL=https://youtube-media-downloader.p.rapidapi.com/v2/
(keep the trailing/– Retrofit requires it)YOUTUBE_HOST=youtube-media-downloader.p.rapidapi.com
These values are loaded in app/build.gradle.kts into BuildConfig:
BuildConfig.YOUTUBE_API_KEYBuildConfig.YOUTUBE_BASE_URLBuildConfig.YOUTUBE_HOST
After editing keys.properties, always Sync Gradle.
-
Base Retrofit client & headers:
app/src/main/java/dev/korryr/tubefetch/di/AppModule.kt- Adds on every request:
x-rapidapi-key: BuildConfig.YOUTUBE_API_KEYx-rapidapi-host: BuildConfig.YOUTUBE_HOST
- Uses
BuildConfig.YOUTUBE_BASE_URLas.baseUrl(...).
- Adds on every request:
-
Retrofit interface for RapidAPI:
data/remote/YouTubeWebService.kt-
Main endpoint used:
@GET("/v2/video/details") suspend fun getVideoDetails( @Query("videoId") videoId: String, @Query("urlAccess") urlAccess: String = "normal", @Query("videos") videos: String = "auto", @Query("audios") audios: String = "auto" ): VideoInfoResponse
-
-
Wrapper around Retrofit + mapping:
data/remote/YouTubeWebServiceImpl.kt- Extracts
videoIdfrom any YouTube URL (watch, youtu.be, embed). - Calls
getVideoDetails(...). - Maps
VideoInfoResponse→ domainVideoInfo. - Picks the correct stream URL from
videos.items/audios.itemsfor downloads.
- Extracts
-
Repository using the wrapper:
data/repo/VideoRepositoryImpl.ktanalyzeVideo(url)→youTubeWebService.getVideoInfo(url).downloadVideo(request)→youTubeWebService.getDownloadUrl(request.url, request.format.extension)→ downloads the returned URL with OkHttp.
- Get the new key from the RapidAPI dashboard.
- Update
YOUTUBE_API_KEYinkeys.properties. - Sync Gradle and rebuild.
Nothing else in code needs to change as long as you stay on the same RapidAPI API (same host and base URL).
-
If RapidAPI changes paths (e.g. new version):
- Update
YOUTUBE_BASE_URLinkeys.propertiesto the new base. - Update paths / query params in
YouTubeWebService.ktto match the new docs. - If the JSON response shape changes, adjust
VideoInfoResponse.ktand the mapping inYouTubeWebServiceImpl.toVideoInfo()/getDownloadUrl().
- Update
-
If you switch away from RapidAPI entirely:
- Replace the Retrofit interface in
YouTubeWebService.ktwith the new service’s endpoints. - Keep the domain layer contracts (
VideoRepository,VideoInfo,DownloadRequest, etc.) the same to avoid touching the UI. - Update
AppModule.provideOkHttpClientif headers or auth mechanism change.
- Replace the Retrofit interface in
If downloads or analysis stop working, verify in this order:
keys.propertiesexists locally and has non-empty values.- Your RapidAPI subscription is active and not rate-limited.
- The sample curl from RapidAPI’s dashboard works with your key.
YOUTUBE_BASE_URL, endpoint path inYouTubeWebService.kt, and the curl URL all match.
Use Logcat’s HTTP logs (OkHttp interceptor) to see the exact URL, status code, and error message returned by RapidAPI.