diff --git a/app/build.gradle b/app/build.gradle index a31befa7..92ac06f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -156,6 +156,7 @@ dependencies { implementation "io.github.junkfood02.youtubedl-android:aria2c:0.18.1" // implementation "io.github.junkfood02.youtubedl-android:library:0.17.4" + //noinspection NewerVersionAvailable implementation "io.github.junkfood02.youtubedl-android:ffmpeg:0.17.2" // implementation "io.github.junkfood02.youtubedl-android:aria2c:0.17.2" @@ -231,5 +232,4 @@ dependencies { implementation("commons-io:commons-io:2.5") implementation("org.apache.commons:commons-compress:1.12") implementation("androidx.core:core-splashscreen:1.2.0") - implementation 'com.github.woheller69:FreeDroidWarn:V1.6' } diff --git a/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt b/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt index 36a36db6..36a25729 100644 --- a/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt +++ b/app/src/main/java/com/deniscerri/ytdl/MainActivity.kt @@ -1,7 +1,6 @@ package com.deniscerri.ytdl import android.app.ActionBar.LayoutParams -import android.app.AlertDialog import android.content.Context import android.content.DialogInterface import android.content.Intent @@ -13,14 +12,12 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import android.util.Log -import android.view.LayoutInflater import android.view.View import android.view.WindowInsets import android.widget.CheckBox import android.widget.TextView import android.widget.Toast import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen import androidx.core.view.WindowInsetsCompat import androidx.core.view.forEach import androidx.core.view.isVisible @@ -70,7 +67,6 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext -import org.woheller69.freeDroidWarn.FreeDroidWarn import java.io.BufferedReader import java.io.InputStreamReader import java.io.Reader @@ -272,7 +268,6 @@ class MainActivity : BaseActivity() { cookieViewModel.updateCookiesFile() val intent = intent - FreeDroidWarn.showWarningOnUpgrade(this, BuildConfig.VERSION_CODE); handleIntents(intent) if (preferences.getBoolean("auto_update_ytdlp", false)){ diff --git a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt index 29e068e7..300e6d3c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/Extensions.kt @@ -627,6 +627,10 @@ object Extensions { return Pattern.compile("((^(https?)://)?(www.)?(m.)?youtu(.be)?(be.com))/watch_videos\\?video_ids=.*").matcher(this).find() } + fun String.isSoundCloudURL() : Boolean { + return Pattern.compile("""^(https?://)?(www\.|m\.)?soundcloud\.com/[\w\-.]+(/[\w\-.]+)*/?$""").matcher(this).find() + } + fun String.extractURL() : String { val res = Pattern.compile("(http|ftp|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])") diff --git a/app/src/main/java/com/deniscerri/ytdl/util/FileUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/FileUtil.kt index 4c5aef88..392ddb7c 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/FileUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/FileUtil.kt @@ -329,6 +329,10 @@ object FileUtil { return "${getCachePath(context)}dl" } + fun getCacheYTDLPPath(context: Context) : String { + return "${getCachePath(context)}yt-dlp" + } + fun getInfoJsonPath(context: Context) : String { return "${getCachePath(context)}infojsons" } diff --git a/app/src/main/java/com/deniscerri/ytdl/util/extractors/ytdlp/YTDLPUtil.kt b/app/src/main/java/com/deniscerri/ytdl/util/extractors/ytdlp/YTDLPUtil.kt index 15e2911b..668e52c8 100644 --- a/app/src/main/java/com/deniscerri/ytdl/util/extractors/ytdlp/YTDLPUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdl/util/extractors/ytdlp/YTDLPUtil.kt @@ -26,6 +26,7 @@ import com.deniscerri.ytdl.database.viewmodel.ResultViewModel import com.deniscerri.ytdl.util.Extensions.getIDFromYoutubeURL import com.deniscerri.ytdl.util.Extensions.getIntByAny import com.deniscerri.ytdl.util.Extensions.getStringByAny +import com.deniscerri.ytdl.util.Extensions.isSoundCloudURL import com.deniscerri.ytdl.util.Extensions.isURL import com.deniscerri.ytdl.util.Extensions.isYoutubeURL import com.deniscerri.ytdl.util.Extensions.isYoutubeWatchVideosURL @@ -104,6 +105,15 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co } } + private fun canApplyFlatPlaylist(url: String) : Boolean { + var noFlatPlaylist = sharedPreferences.getBoolean("no_flat_playlist", false) + if (url.isSoundCloudURL()) { + noFlatPlaylist = true + } + + return !noFlatPlaylist + } + @SuppressLint("RestrictedApi") fun getFromYTDL(query: String, singleItem: Boolean = false, resultsGenerated: (results: List) -> Unit): List { val searchEngine = sharedPreferences.getString("search_engine", "ytsearch") @@ -136,7 +146,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co request.setYoutubeExtractorArgs(query) } - if (!sharedPreferences.getBoolean("no_flat_playlist", false)) { + if (canApplyFlatPlaylist(query)) { request.addOption("--flat-playlist") } @@ -181,7 +191,7 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co for (result in results) { if (result.isNullOrBlank()) continue val jsonObject = JSONObject(result) - val title = jsonObject.getStringByAny("alt_title", "title", "webpage_url_basename") + var title = jsonObject.getStringByAny("alt_title", "title", "webpage_url_basename") if (title == "[Private video]" || title == "[Deleted video]") continue @@ -266,10 +276,14 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co val type = jsonObject.getStringByAny("_type") - if (type == "playlist" && playlistTitle.isEmpty()) { - playlistTitle = title + if (type == "playlist") { + if (playlistTitle.isEmpty()) { + playlistTitle = title + } + title = "" } + val availableSubtitles = mutableListOf() if (jsonObject.has("subtitles")) { runCatching { @@ -618,6 +632,8 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co @OptIn(ExperimentalStdlibApi::class) private fun YTDLRequest.addWriteInfoJson(url: String) { + if (url.isYoutubeURL() && url.contains("playlist?list=")) return + val cachePath = FileUtil.getInfoJsonPath(context) File(cachePath).mkdirs() @@ -1240,11 +1256,6 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co var cont = "" val outputContainer = downloadItem.container - if (downloadItem.videoPreferences.compatibilityMode) { - request.addOption("--recode-video", "mp4") - request.addOption("--merge-output-format", "mp4/mkv") - request.addOption("--ppa", "VideoConvertor+ffmpeg_o:-c:v libx264 -c:a aac -profile:v baseline") - } if(outputContainer.isNotEmpty() && outputContainer != "Default" && outputContainer != context.getString( R.string.defaultValue) && supportedContainers.contains(outputContainer)){ @@ -1301,7 +1312,13 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co val preferredCodec = sharedPreferences.getString("video_codec", "") val vCodecPrefIndex = context.getStringArray(R.array.video_codec_values).indexOf(preferredCodec) - val vCodecPref = context.getStringArray(R.array.video_codec_values_ytdlp)[vCodecPrefIndex] + var vCodecPref = context.getStringArray(R.array.video_codec_values_ytdlp)[vCodecPrefIndex] + + if (downloadItem.videoPreferences.compatibilityMode) { + request.addOption("--recode-video", "mp4") + request.addOption("--merge-output-format", "mp4/mkv") + request.addOption("--ppa", "VideoConvertor+ffmpeg_o:-c:v libx264 -c:a aac -profile:v baseline") + } val defaultFormats = context.resources.getStringArray(R.array.video_formats_values) val usingGenericFormat = defaultFormats.contains(videoF) || downloadItem.allFormats.isEmpty() || downloadItem.allFormats == formatUtil.getGenericVideoFormats(context.resources) @@ -1552,7 +1569,8 @@ class YTDLPUtil(private val context: Context, private val commandTemplateDao: Co tmp.addOption("--config-locations", conf.absolutePath) ytDlRequest.addCommands(tmp) - ytDlRequest.addOption("--cache-dir", cache.absolutePath) + val ytdlpCache = File(FileUtil.getCacheYTDLPPath(context)) + ytDlRequest.addOption("--cache-dir", ytdlpCache.absolutePath) return ytDlRequest } } \ No newline at end of file