inner class DownloadBinder : Binder() { fun getService(): VideoDownloaderService = this@VideoDownloaderService }
<LinearLayout android:id="@+id/samplesContainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:orientation="vertical" />
private fun checkPermissionsAndDownload(url: String, fileName: String) { val permissions = mutableListOf<String>() if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE) } } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { permissions.add(Manifest.permission.POST_NOTIFICATIONS) } } if (permissions.isNotEmpty()) { permissionLauncher.launch(permissions.toTypedArray()) } else { startDownload(url, fileName) } }
<com.google.android.material.button.MaterialButton android:id="@+id/btnDownload" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:text="Download Video" app:icon="@android:drawable/stat_sys_download" /> download 4k video from youtube android
override fun onBind(intent: Intent?): IBinder = binder
// Coroutines implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
<com.google.android.material.button.MaterialButton android:id="@+id/btnOpenDownloads" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="Open Downloads" style="@style/Widget.MaterialComponents.Button.OutlinedButton" /> inner class DownloadBinder : Binder() { fun getService():
<com.google.android.material.textfield.TextInputLayout android:layout_width="match_parent" android:layout_height="wrap_content" style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" android:hint="Video URL">
fun downloadVideo(url: String, fileName: String, onProgress: (Float) -> Unit, onComplete: (File?) -> Unit) { serviceScope.launch { try { startForegroundWithNotification() val request = Request.Builder().url(url).build() val response = client.newCall(request).execute() if (!response.isSuccessful) { withContext(Dispatchers.Main) { onComplete(null) } return@launch } val contentLength = response.body?.contentLength() ?: -1L val inputStream = response.body?.byteStream() val downloadsDir = getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) val outputFile = File(downloadsDir, "$fileName.mp4") FileOutputStream(outputFile).use { outputStream -> val buffer = ByteArray(8192) var bytesRead: Int var totalBytesRead = 0L while (inputStream?.read(buffer).also { bytesRead = it ?: -1 } != -1) { outputStream.write(buffer, 0, bytesRead) totalBytesRead += bytesRead if (contentLength > 0) { val progress = (totalBytesRead.toFloat() / contentLength) * 100 withContext(Dispatchers.Main) { onProgress(progress) updateNotification(progress.toInt()) } } } } inputStream?.close() withContext(Dispatchers.Main) { onComplete(outputFile) } stopForeground(false) } catch (e: Exception) { e.printStackTrace() withContext(Dispatchers.Main) { onComplete(null) } } } }
I can't directly download videos from YouTube as it violates YouTube's Terms of Service (only official YouTube Premium allows offline downloads within their app). private fun checkPermissionsAndDownload(url: String
<com.google.android.material.textfield.TextInputEditText android:id="@+id/etUrl" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textUri" /> </com.google.android.material.textfield.TextInputLayout>
<application android:requestLegacyExternalStorage="true" ... > dependencies { implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.11.0") // Networking implementation("com.squareup.okhttp3:okhttp:4.12.0") implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
private fun openFile(file: File) { val intent = Intent(Intent.ACTION_VIEW).apply { setDataAndType(Uri.fromFile(file), "video/mp4") addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) } startActivity(Intent.createChooser(intent, "Play Video")) }
data class SampleVideo(val name: String, val url: String) } <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical">