diff --git a/app/build.gradle b/app/build.gradle index 7ac6dc06..c9e1065a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,12 @@ def properties = new Properties() def versionMajor = 1 def versionMinor = 6 def versionPatch = 3 -def versionBuild = 0 // bump for dogfood builds, public betas, etc. +def versionBuild = 1 // bump for dogfood builds, public betas, etc. +def versionExt = "" + +if (versionBuild > 0){ + versionExt = ".${versionBuild}-beta" +} android { namespace 'com.deniscerri.ytdlnis' @@ -37,7 +42,7 @@ android { minSdk 23 targetSdk 33 versionCode versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild - versionName "${versionMajor}.${versionMinor}.${versionPatch}" + versionName "${versionMajor}.${versionMinor}.${versionPatch}${versionExt}" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" archivesBaseName = "YTDLnis-$versionName" vectorDrawables { @@ -181,10 +186,8 @@ dependencies { api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVer" api "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVer" - implementation "com.squareup.retrofit2:retrofit:$retrofitVer" - implementation "com.squareup.retrofit2:converter-gson:$retrofitVer" + implementation 'com.google.code.gson:gson:2.9.1' implementation "com.squareup.okhttp3:okhttp:5.0.0-alpha.10" - implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation "com.google.android.exoplayer:exoplayer:2.18.5" diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index dcb57de3..3558898c 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -24,7 +24,7 @@ -keep class com.google.gson.** { *; } -keep class com.deniscerri.ytdlnis.database.models.AudioPreferences -keep class com.deniscerri.ytdlnis.database.models.VideoPreferences --keepclassmembers class * { +-keepclassmembers,allowobfuscation class * { @com.google.gson.annotations.SerializedName ; } -keepclassmembers class <1> { @@ -67,6 +67,9 @@ -keepclassmembers class * extends androidx.work.Worker { public (android.content.Context,androidx.work.WorkerParameters); } +-keep @androidx.room.Entity class * +-keep class * extends androidx.room.RoomDatabase +-dontwarn androidx.room.paging.** -dontwarn com.google.android.exoplayer2.** # Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher. diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt index 3c19d8b7..e34381b2 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/repository/ResultRepository.kt @@ -50,17 +50,18 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp suspend fun getOne(inputQuery: String, resetResults: Boolean) : ArrayList{ val infoUtil = InfoUtil(context) - val query = infoUtil.getIDFromYoutubeURL(inputQuery) try { - val v = infoUtil.getVideo(query) + val v = infoUtil.getVideo(inputQuery) if (resetResults) { deleteAll() - itemCount.value = 1 + itemCount.value = v.size }else{ - v!!.playlistTitle = "ytdlnis-Search" + v.forEach { it?.playlistTitle = "ytdlnis-Search" } } - resultDao.insert(v!!) - return arrayListOf(v) + v.forEach { + resultDao.insert(it!!) + } + return ArrayList(v) } catch (e: Exception) { Log.e(tag, e.toString()) } @@ -82,10 +83,10 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp if (tmpToken == nextPageToken) break nextPageToken = tmpToken } while (true) + itemCount.value = items.size items.forEach { resultDao.insert(it!!) } - itemCount.value = items.size return items } @@ -122,10 +123,6 @@ class ResultRepository(private val resultDao: ResultDao, private val commandTemp resultDao.update(item) } - fun getTemplates() : List { - return commandTemplateDao.getAllTemplates() - } - fun getItemByURL(url: String): ResultItem { return resultDao.getResultByURL(url) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt index 8edee5dd..920dd7d7 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/database/viewmodel/ResultViewModel.kt @@ -85,10 +85,10 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) "Search" -> { res = repository.search(inputQuery, resetResults) } - "Video" -> { + "YT_Video" -> { res = repository.getOne(inputQuery, resetResults) } - "Playlist" -> { + "YT_Playlist" -> { res = repository.getPlaylist(inputQuery, resetResults) } "Default" -> { @@ -107,9 +107,9 @@ class ResultViewModel(application: Application) : AndroidViewModel(application) val p = Pattern.compile("^(https?)://(www.)?(music.)?youtu(.be)?") val m = p.matcher(inputQuery) if (m.find()) { - type = "Video" + type = "YT_Video" if (inputQuery.contains("playlist?list=")) { - type = "Playlist" + type = "YT_Playlist" } } else if (inputQuery.contains("http")) { type = "Default" diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt index 5e8bafc0..89ef0c88 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloads/QueuedDownloadsFragment.kt @@ -357,6 +357,7 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi when (direction) { ItemTouchHelper.LEFT -> { val deletedItem = items[position] + queuedDownloads.notifyItemChanged(position) removeItem(deletedItem.id) } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt index 76cbe052..ac2ed9d5 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/InfoUtil.kt @@ -12,13 +12,13 @@ import com.deniscerri.ytdlnis.database.models.ChapterItem import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.ResultItem import com.google.gson.Gson +import com.google.gson.GsonBuilder import com.google.gson.reflect.TypeToken import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDLRequest import org.json.JSONArray import org.json.JSONException import org.json.JSONObject -import retrofit2.Retrofit import java.io.BufferedReader import java.io.File import java.io.InputStreamReader @@ -32,7 +32,6 @@ import java.util.regex.Pattern class InfoUtil(private val context: Context) { private var items: ArrayList private lateinit var sharedPreferences: SharedPreferences - private lateinit var retrofit : Retrofit private var key: String? = null init { @@ -146,7 +145,9 @@ class InfoUtil(private val context: Context) { var nextpage = res.getString("nextpage") for (i in 0 until dataArray.length()){ val obj = dataArray.getJSONObject(i) - items.add(createVideoFromPipedJSON(obj, obj.getString("url").removePrefix("/watch?v="))) + val itm = createVideoFromPipedJSON(obj, obj.getString("url").removePrefix("/watch?v=")) + itm?.playlistTitle = "YTDLnis" + items.add(itm) } if (nextpage == "null") nextpage = "" return PlaylistTuple(nextpage, items) @@ -211,20 +212,20 @@ class InfoUtil(private val context: Context) { } @Throws(JSONException::class) - fun getVideo(id: String): ResultItem? { + fun getVideo(url: String): List { try { - + val id = getIDFromYoutubeURL(url) if (key!!.isEmpty()) { val res = genericRequest("$pipedURL/streams/$id") - return if (res.length() == 0) getFromYTDL("https://www.youtube.com/watch?v=$id")[0] else createVideoFromPipedJSON( + return if (res.length() == 0) getFromYTDL(url) else listOf(createVideoFromPipedJSON( res, id - ) + )) } //short data var res = genericRequest("https://youtube.googleapis.com/youtube/v3/videos?part=snippet,contentDetails&id=$id&key=$key") - if (!res.has("items")) return getFromYTDL("https://www.youtube.com/watch?v=$id")[0] + if (!res.has("items")) return getFromYTDL(url) var duration = res.getJSONArray("items").getJSONObject(0).getJSONObject("contentDetails") .getString("duration") duration = formatDuration(duration) @@ -232,9 +233,9 @@ class InfoUtil(private val context: Context) { res.put("videoID", id) res.put("duration", duration) fixThumbnail(res) - return createVideofromJSON(res) + return listOf(createVideofromJSON(res)) }catch (e: Exception){ - return getFromYTDL("https://www.youtube.com/watch?v=$id")[0] + return getFromYTDL(url) } } @@ -697,9 +698,12 @@ class InfoUtil(private val context: Context) { } else { jsonObject.getString("webpage_url_basename") } - var author: String? = "" - if (jsonObject.has("uploader")) { - author = jsonObject.getString("uploader") + var author: String = if (jsonObject.has("uploader")) jsonObject.getString("uploader") else "" + if (author.isEmpty() || author == "null"){ + author = if (jsonObject.has("channel")) jsonObject.getString("channel") else "" + if (author.isEmpty() || author == "null"){ + author = if (jsonObject.has("playlist_uploader")) jsonObject.getString("playlist_uploader") else "" + } } var duration = "" runCatching { @@ -747,7 +751,7 @@ class InfoUtil(private val context: Context) { } } - val chaptersInJSON = if (jsonObject.has("formats") && jsonObject.get("formats") is JSONArray) jsonObject.getJSONArray("formats") else null + val chaptersInJSON = if (jsonObject.has("chapters") && jsonObject.get("chapters") is JSONArray) jsonObject.getJSONArray("chapters") else null val listType: Type = object : TypeToken>() {}.type var chapters : ArrayList = arrayListOf() @@ -803,9 +807,12 @@ class InfoUtil(private val context: Context) { val youtubeDLResponse = YoutubeDL.getInstance().execute(request) val jsonObject = JSONObject(youtubeDLResponse.out) - var author: String? = "" - if (jsonObject.has("uploader")) { - author = jsonObject.getString("uploader") + var author: String = if (jsonObject.has("uploader")) jsonObject.getString("uploader") else "" + if (author.isEmpty() || author == "null"){ + author = if (jsonObject.has("channel")) jsonObject.getString("channel") else "" + if (author.isEmpty() || author == "null"){ + author = if (jsonObject.has("playlist_uploader")) jsonObject.getString("playlist_uploader") else "" + } } var duration = "" diff --git a/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt b/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt index 8d088f4b..dc57f873 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/util/UpdateUtil.kt @@ -49,7 +49,7 @@ class UpdateUtil(var context: Context) { return } val versionNameInt = version.split("v")[1].replace(".","").toInt() - val currentVersionNameInt = BuildConfig.VERSION_NAME.replace(".","").toInt() + val currentVersionNameInt = BuildConfig.VERSION_CODE.toString().replace("0", "").substring(0, versionNameInt.toString().length).toInt() if (currentVersionNameInt >= versionNameInt) { result(context.getString(R.string.you_are_in_latest_version)) return diff --git a/app/src/main/res/layout/download_card.xml b/app/src/main/res/layout/download_card.xml index 66b9d353..1c97e79b 100644 --- a/app/src/main/res/layout/download_card.xml +++ b/app/src/main/res/layout/download_card.xml @@ -132,7 +132,7 @@ app:layout_constraintTop_toTopOf="parent" /> bn bs de + el es fa fr diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml index 42e0204b..19ed0e46 100644 --- a/app/src/main/res/xml/locales_config.xml +++ b/app/src/main/res/xml/locales_config.xml @@ -6,6 +6,7 @@ +