1.7.9.1 prep
This commit is contained in:
parent
c40095ac7f
commit
087ba0781a
38 changed files with 642 additions and 369 deletions
|
|
@ -201,4 +201,5 @@ dependencies {
|
||||||
implementation 'androidx.compose.material3:material3-android:1.2.1'
|
implementation 'androidx.compose.material3:material3-android:1.2.1'
|
||||||
implementation "io.noties.markwon:core:4.6.2"
|
implementation "io.noties.markwon:core:4.6.2"
|
||||||
implementation("org.greenrobot:eventbus:3.3.1")
|
implementation("org.greenrobot:eventbus:3.3.1")
|
||||||
|
//implementation("com.github.TeamNewPipe:NewPipeExtractor:0.24.2")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
6
app/proguard-rules.pro
vendored
6
app/proguard-rules.pro
vendored
|
|
@ -88,5 +88,11 @@
|
||||||
static <1>$Companion Companion;
|
static <1>$Companion Companion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
### Rules for NewPipeExtractor
|
||||||
|
#-keep class org.schabi.newpipe.extractor.timeago.patterns.** { *; }
|
||||||
|
#-keep class org.mozilla.javascript.** { *; }
|
||||||
|
#-keep class org.mozilla.classfile.ClassFileWriter
|
||||||
|
#-dontwarn org.mozilla.javascript.tools.**
|
||||||
|
|
||||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||||
-dontobfuscate
|
-dontobfuscate
|
||||||
|
|
|
||||||
|
|
@ -80,24 +80,46 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" android:host="youtube.com" />
|
||||||
<data
|
|
||||||
android:scheme="https"
|
|
||||||
android:host="youtube.com" />
|
|
||||||
<data android:host="youtube.com" />
|
<data android:host="youtube.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.youtube.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.youtu.be" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="youtu.be" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="twitter.com" />
|
<data android:host="twitter.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.twitter.com" />
|
||||||
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
|
|
@ -114,7 +136,7 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="soundcloud.com" />
|
<data android:host="www.x.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
@ -122,162 +144,177 @@
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="soundcloud.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.soundcloud.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="facebook.com" />
|
<data android:host="facebook.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="www.facebook.com" />
|
<data android:host="www.facebook.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="fb.watch" />
|
<data android:host="fb.watch" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="instagram.com" />
|
<data android:host="instagram.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="www.instagram.com" />
|
<data android:host="www.instagram.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="tiktok.com" />
|
<data android:host="tiktok.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.tiktok.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="vm.tiktok.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="bilibili.tv" />
|
<data android:host="bilibili.tv" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="youtu.be" />
|
<data android:host="www.bilibili.tv" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="twitch.com" />
|
<data android:host="twitch.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="reddit.com" />
|
<data android:host="www.twitch.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="www.reddit.com" />
|
<data android:host="www.reddit.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="reddit.com" />
|
<data android:host="reddit.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="m.reddit.com" />
|
<data android:host="m.reddit.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="pinterest.com" />
|
<data android:host="pinterest.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.pinterest.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="music.youtube.com" />
|
<data android:host="music.youtube.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="m.youtube.com" />
|
<data android:host="m.youtube.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="vk.com" />
|
<data android:host="vk.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.VIEW" />
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.vk.com" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
<data android:host="rutube.com" />
|
<data android:host="rutube.com" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="www.rutube.com" />
|
||||||
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ package com.deniscerri.ytdl
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.ActionBar.LayoutParams
|
import android.app.ActionBar.LayoutParams
|
||||||
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.DialogInterface
|
import android.content.DialogInterface
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
|
@ -32,6 +33,7 @@ import androidx.fragment.app.FragmentContainerView
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
|
|
@ -290,9 +292,6 @@ class MainActivity : BaseActivity() {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||||
super.onSaveInstanceState(savedInstanceState)
|
super.onSaveInstanceState(savedInstanceState)
|
||||||
|
|
@ -442,6 +441,8 @@ class MainActivity : BaseActivity() {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}else if (action == Intent.ACTION_VIEW){
|
}else if (action == Intent.ACTION_VIEW){
|
||||||
|
navController.popBackStack(navController.graph.startDestinationId, true)
|
||||||
|
|
||||||
when(intent.getStringExtra("destination")){
|
when(intent.getStringExtra("destination")){
|
||||||
"Downloads" -> {
|
"Downloads" -> {
|
||||||
navController.navigate(R.id.historyFragment)
|
navController.navigate(R.id.historyFragment)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import androidx.room.Query
|
||||||
import androidx.room.Transaction
|
import androidx.room.Transaction
|
||||||
import androidx.room.Update
|
import androidx.room.Update
|
||||||
import com.deniscerri.ytdl.database.models.LogItem
|
import com.deniscerri.ytdl.database.models.LogItem
|
||||||
|
import com.deniscerri.ytdl.util.Extensions.appendLineToLog
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
|
|
@ -43,10 +44,10 @@ interface LogDao {
|
||||||
suspend fun updateLog(line: String, id: Long, resetLog: Boolean = false) {
|
suspend fun updateLog(line: String, id: Long, resetLog: Boolean = false) {
|
||||||
val l = getByID(id) ?: return
|
val l = getByID(id) ?: return
|
||||||
var log = l.content ?: ""
|
var log = l.content ?: ""
|
||||||
if (resetLog) {
|
log = if (resetLog) {
|
||||||
log = line.lines().joinToString("\n")
|
line.appendLineToLog()
|
||||||
}else{
|
}else{
|
||||||
log += "\n${line}"
|
log.appendLineToLog(line)
|
||||||
}
|
}
|
||||||
updateLogContent(log, id)
|
updateLogContent(log, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import androidx.room.Insert
|
||||||
import androidx.room.Query
|
import androidx.room.Query
|
||||||
import androidx.room.Transaction
|
import androidx.room.Transaction
|
||||||
import com.deniscerri.ytdl.database.models.TerminalItem
|
import com.deniscerri.ytdl.database.models.TerminalItem
|
||||||
|
import com.deniscerri.ytdl.util.Extensions.appendLineToLog
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
|
||||||
@Dao
|
@Dao
|
||||||
|
|
@ -31,10 +32,10 @@ interface TerminalDao {
|
||||||
suspend fun updateLog(line: String, id: Long, resetLog : Boolean = false){
|
suspend fun updateLog(line: String, id: Long, resetLog : Boolean = false){
|
||||||
val t = getTerminalById(id) ?: return
|
val t = getTerminalById(id) ?: return
|
||||||
var log = t.log ?: ""
|
var log = t.log ?: ""
|
||||||
if (resetLog) {
|
log = if (resetLog) {
|
||||||
log = line.lines().joinToString("\n")
|
line.lines().joinToString("\n")
|
||||||
}else{
|
}else{
|
||||||
log += "\n${line}"
|
log.appendLineToLog(line)
|
||||||
}
|
}
|
||||||
updateTerminalLog(log, id)
|
updateTerminalLog(log, id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
|
@ -148,7 +149,16 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
|
|
||||||
|
|
||||||
val confTmp = Configuration(application.resources.configuration)
|
val confTmp = Configuration(application.resources.configuration)
|
||||||
confTmp.setLocale(Locale(sharedPreferences.getString("app_language", "en")!!))
|
val locale = if (Build.VERSION.SDK_INT < 33) {
|
||||||
|
sharedPreferences.getString("app_language", "")!!.ifEmpty { Locale.getDefault().language }
|
||||||
|
}else{
|
||||||
|
Locale.getDefault().language
|
||||||
|
}.run {
|
||||||
|
split("-")
|
||||||
|
}.run {
|
||||||
|
if (this.size == 1) Locale(this[0]) else Locale(this[0], this[1])
|
||||||
|
}
|
||||||
|
confTmp.setLocale(locale)
|
||||||
val metrics = DisplayMetrics()
|
val metrics = DisplayMetrics()
|
||||||
resources = Resources(application.assets, metrics, confTmp)
|
resources = Resources(application.assets, metrics, confTmp)
|
||||||
}
|
}
|
||||||
|
|
@ -245,6 +255,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
|
|
||||||
|
|
||||||
val preferredAudioFormats = getPreferredAudioFormats(resultItem.formats)
|
val preferredAudioFormats = getPreferredAudioFormats(resultItem.formats)
|
||||||
|
val subsLanguages = sharedPreferences.getString("subs_lang", "en.*,.*-orig")!!
|
||||||
|
|
||||||
val videoPreferences = VideoPreferences(
|
val videoPreferences = VideoPreferences(
|
||||||
embedSubs,
|
embedSubs,
|
||||||
|
|
@ -252,6 +263,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
ArrayList(sponsorblock),
|
ArrayList(sponsorblock),
|
||||||
saveSubs,
|
saveSubs,
|
||||||
saveAutoSubs,
|
saveAutoSubs,
|
||||||
|
subsLanguages,
|
||||||
audioFormatIDs = preferredAudioFormats,
|
audioFormatIDs = preferredAudioFormats,
|
||||||
recodeVideo = recodeVideo
|
recodeVideo = recodeVideo
|
||||||
)
|
)
|
||||||
|
|
@ -354,8 +366,8 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
val format = getFormat(it.allFormats, type)
|
val format = getFormat(it.allFormats, type)
|
||||||
it.format = format
|
it.format = format
|
||||||
|
|
||||||
var updatedDownloadPath: String = ""
|
var updatedDownloadPath = ""
|
||||||
var container: String = ""
|
var container = ""
|
||||||
|
|
||||||
when(type){
|
when(type){
|
||||||
Type.audio -> {
|
Type.audio -> {
|
||||||
|
|
@ -363,11 +375,11 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
container = sharedPreferences.getString("audio_format", "")!!
|
container = sharedPreferences.getString("audio_format", "")!!
|
||||||
}
|
}
|
||||||
Type.video -> {
|
Type.video -> {
|
||||||
updatedDownloadPath = sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath())!!
|
updatedDownloadPath = sharedPreferences.getString("video_path", FileUtil.getDefaultVideoPath())!!
|
||||||
container = sharedPreferences.getString("audio_format", "")!!
|
container = sharedPreferences.getString("video_format", "")!!
|
||||||
}
|
}
|
||||||
Type.command -> {
|
Type.command -> {
|
||||||
updatedDownloadPath = sharedPreferences.getString("music_path", FileUtil.getDefaultAudioPath())!!
|
updatedDownloadPath = sharedPreferences.getString("command_path", FileUtil.getDefaultCommandPath())!!
|
||||||
container = ""
|
container = ""
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|
@ -391,6 +403,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
|
val saveThumb = sharedPreferences.getBoolean("write_thumbnail", false)
|
||||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||||
val cropThumb = sharedPreferences.getBoolean("crop_thumbnail", false)
|
val cropThumb = sharedPreferences.getBoolean("crop_thumbnail", false)
|
||||||
|
val subsLanguages = sharedPreferences.getString("subs_lang", "en.*,.*-orig")!!
|
||||||
|
|
||||||
val customFileNameTemplate = when(historyItem.type) {
|
val customFileNameTemplate = when(historyItem.type) {
|
||||||
Type.audio -> sharedPreferences.getString("file_name_template_audio", "%(uploader).30B - %(title).170B")
|
Type.audio -> sharedPreferences.getString("file_name_template_audio", "%(uploader).30B - %(title).170B")
|
||||||
|
|
@ -420,7 +433,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
}
|
}
|
||||||
|
|
||||||
val audioPreferences = AudioPreferences(embedThumb, cropThumb,false, ArrayList(sponsorblock!!))
|
val audioPreferences = AudioPreferences(embedThumb, cropThumb,false, ArrayList(sponsorblock!!))
|
||||||
val videoPreferences = VideoPreferences(embedSubs, addChapters, false, ArrayList(sponsorblock), saveSubs, saveAutoSubs, recodeVideo = recodeVideo)
|
val videoPreferences = VideoPreferences(embedSubs, addChapters, false, ArrayList(sponsorblock), saveSubs, saveAutoSubs, subsLanguages, recodeVideo = recodeVideo)
|
||||||
var path = defaultPath
|
var path = defaultPath
|
||||||
historyItem.downloadPath.first().apply {
|
historyItem.downloadPath.first().apply {
|
||||||
File(this).parent?.apply {
|
File(this).parent?.apply {
|
||||||
|
|
@ -930,10 +943,13 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
|
||||||
}else{
|
}else{
|
||||||
val queued = repository.updateAll(queuedItems)
|
val queued = repository.updateAll(queuedItems)
|
||||||
|
|
||||||
if (!sharedPreferences.getBoolean("paused_downloads", false)) {
|
if (sharedPreferences.getBoolean("paused_downloads", true)) {
|
||||||
result.message = repository.startDownloadWorker(queued, context).getOrElse { "" }
|
sharedPreferences.edit().putBoolean("paused_downloads", false).apply()
|
||||||
|
resetActiveToQueued()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result.message = repository.startDownloadWorker(queued, context).getOrElse { "" }
|
||||||
|
|
||||||
if(!useScheduler){
|
if(!useScheduler){
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
queued.filter { it.downloadStartTime != 0L && (it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty()) }.forEach {
|
queued.filter { it.downloadStartTime != 0L && (it.title.isEmpty() || it.author.isEmpty() || it.thumb.isEmpty()) }.forEach {
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,16 @@ import com.deniscerri.ytdl.database.repository.SearchHistoryRepository
|
||||||
import com.deniscerri.ytdl.util.InfoUtil
|
import com.deniscerri.ytdl.util.InfoUtil
|
||||||
import com.deniscerri.ytdl.util.NotificationUtil
|
import com.deniscerri.ytdl.util.NotificationUtil
|
||||||
import com.yausername.youtubedl_android.YoutubeDLException
|
import com.yausername.youtubedl_android.YoutubeDLException
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.update
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.joinAll
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Semaphore
|
||||||
|
import kotlinx.coroutines.sync.withPermit
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -40,18 +45,13 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
private val dao: ResultDao
|
private val dao: ResultDao
|
||||||
data class ResultsUiState(
|
data class ResultsUiState(
|
||||||
var processing: Boolean,
|
var processing: Boolean,
|
||||||
var errorMessage: Pair<Int, String>?,
|
var errorMessage: String?,
|
||||||
var actions: MutableList<Pair<Int, ResultAction>>?
|
var canContinueOnError: Boolean = false
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class ResultAction {
|
|
||||||
COPY_LOG
|
|
||||||
}
|
|
||||||
|
|
||||||
val uiState: MutableStateFlow<ResultsUiState> = MutableStateFlow(ResultsUiState(
|
val uiState: MutableStateFlow<ResultsUiState> = MutableStateFlow(ResultsUiState(
|
||||||
processing = false,
|
processing = false,
|
||||||
errorMessage = null,
|
errorMessage = null,
|
||||||
actions = null
|
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -63,7 +63,8 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
var updateFormatsResultData: MutableStateFlow<MutableList<Format>?> = MutableStateFlow(null)
|
var updateFormatsResultData: MutableStateFlow<MutableList<Format>?> = MutableStateFlow(null)
|
||||||
private var updateFormatsResultDataJob: Job? = null
|
private var updateFormatsResultDataJob: Job? = null
|
||||||
|
|
||||||
var parsingQueries: Job? = null
|
private var parsingQueries: Job? = null
|
||||||
|
private var parsingQueriesJobList : MutableList<Job> = mutableListOf()
|
||||||
|
|
||||||
private val sharedPreferences: SharedPreferences
|
private val sharedPreferences: SharedPreferences
|
||||||
|
|
||||||
|
|
@ -101,6 +102,7 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
|
|
||||||
fun cancelParsingQueries(){
|
fun cancelParsingQueries(){
|
||||||
parsingQueries?.cancel(CancellationException())
|
parsingQueries?.cancel(CancellationException())
|
||||||
|
parsingQueriesJobList.forEach { it.cancel(CancellationException()) }
|
||||||
uiState.update {it.copy(processing = false)}
|
uiState.update {it.copy(processing = false)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,23 +112,29 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
}
|
}
|
||||||
val resetResults = inputQueries.size == 1
|
val resetResults = inputQueries.size == 1
|
||||||
|
|
||||||
uiState.update {it.copy(processing = true, errorMessage = null, actions = null)}
|
uiState.update {it.copy(processing = true, errorMessage = null)}
|
||||||
val res = mutableListOf<ResultItem?>()
|
val res = mutableListOf<ResultItem?>()
|
||||||
inputQueries.forEach { inputQuery ->
|
|
||||||
try {
|
|
||||||
res.addAll(repository.getResultsFromSource(inputQuery, resetResults))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
if (updateResultDataJob?.isCancelled == false || e is YoutubeDLException){
|
|
||||||
uiState.update {it.copy(
|
|
||||||
processing = false,
|
|
||||||
errorMessage = Pair(R.string.no_results, e.message.toString()),
|
|
||||||
actions = mutableListOf(Pair(R.string.copy_log, ResultAction.COPY_LOG))
|
|
||||||
)}
|
|
||||||
Log.e(tag, e.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
val requestSemaphore = Semaphore(10)
|
||||||
|
inputQueries.forEach { inputQuery ->
|
||||||
|
parsingQueriesJobList.add(viewModelScope.launch(Dispatchers.IO){
|
||||||
|
requestSemaphore.withPermit {
|
||||||
|
try {
|
||||||
|
res.addAll(repository.getResultsFromSource(inputQuery, resetResults))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (updateResultDataJob?.isCancelled == false || e is YoutubeDLException){
|
||||||
|
uiState.update {it.copy(
|
||||||
|
processing = false,
|
||||||
|
errorMessage = e.message.toString(),
|
||||||
|
)}
|
||||||
|
Log.e(tag, e.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
parsingQueriesJobList.joinAll()
|
||||||
if (!isForegrounded() && inputQueries.size > 1){
|
if (!isForegrounded() && inputQueries.size > 1){
|
||||||
notificationUtil.showQueriesFinished()
|
notificationUtil.showQueriesFinished()
|
||||||
}
|
}
|
||||||
|
|
@ -279,17 +287,12 @@ class ResultViewModel(private val application: Application) : AndroidViewModel(a
|
||||||
uiState.update {
|
uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
processing = false,
|
processing = false,
|
||||||
errorMessage = Pair(R.string.no_results, e.message.toString()),
|
errorMessage = e.message.toString(),
|
||||||
actions = mutableListOf(
|
|
||||||
Pair(
|
|
||||||
R.string.copy_log,
|
|
||||||
ResultAction.COPY_LOG
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Log.e(tag, e.toString())
|
Log.e(tag, e.toString())
|
||||||
}
|
}
|
||||||
|
updatingFormats.emit(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateFormatsResultDataJob?.start()
|
updateFormatsResultDataJob?.start()
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
private var appBarLayout: AppBarLayout? = null
|
private var appBarLayout: AppBarLayout? = null
|
||||||
private var materialToolbar: MaterialToolbar? = null
|
private var materialToolbar: MaterialToolbar? = null
|
||||||
private var loadingItems: Boolean = false
|
private var loadingItems: Boolean = false
|
||||||
|
private var queryList = mutableListOf<String>()
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
|
|
@ -255,8 +256,28 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
launch{
|
launch{
|
||||||
resultViewModel.uiState.collectLatest { res ->
|
resultViewModel.uiState.collectLatest { res ->
|
||||||
if (res.errorMessage != null){
|
if (res.errorMessage != null){
|
||||||
kotlin.runCatching { UiUtil.handleResultResponse(requireActivity(), res, closed ={}) }
|
val isSingleQueryAndURL = queryList.size == 1 && Patterns.WEB_URL.matcher(queryList.first()).matches()
|
||||||
resultViewModel.uiState.update {it.copy(errorMessage = null, actions = null) }
|
|
||||||
|
kotlin.runCatching { UiUtil.handleNoResults(requireActivity(), res.errorMessage!!, continueAnyway = isSingleQueryAndURL, continued = {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
if (sharedPreferences!!.getBoolean("download_card", true)) {
|
||||||
|
withContext(Dispatchers.Main){
|
||||||
|
showSingleDownloadSheet(
|
||||||
|
resultItem = downloadViewModel.createEmptyResultItem(queryList.first()),
|
||||||
|
type = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!),
|
||||||
|
disableUpdateData = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val downloadItem = downloadViewModel.createDownloadItemFromResult(
|
||||||
|
result = downloadViewModel.createEmptyResultItem(queryList.first()),
|
||||||
|
givenType = DownloadViewModel.Type.valueOf(sharedPreferences!!.getString("preferred_download_type", "video")!!)
|
||||||
|
)
|
||||||
|
downloadViewModel.queueDownloads(listOf(downloadItem))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, closed = {}) }
|
||||||
|
resultViewModel.uiState.update {it.copy(errorMessage = null) }
|
||||||
}
|
}
|
||||||
|
|
||||||
loadingItems = res.processing
|
loadingItems = res.processing
|
||||||
|
|
@ -270,9 +291,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
shimmerCards!!.stopShimmer()
|
shimmerCards!!.stopShimmer()
|
||||||
shimmerCards!!.visibility = GONE
|
shimmerCards!!.visibility = GONE
|
||||||
if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty()){
|
if (resultsList!!.size > 1 && resultsList!![0]!!.playlistTitle.isNotEmpty()){
|
||||||
this@HomeFragment.downloadAllFab!!.visibility = VISIBLE
|
downloadAllFab!!.visibility = VISIBLE
|
||||||
}else{
|
}else{
|
||||||
this@HomeFragment.downloadAllFab!!.visibility = GONE
|
downloadAllFab!!.visibility = GONE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -602,7 +623,7 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
|
|
||||||
private fun initSearch(searchView: SearchView){
|
private fun initSearch(searchView: SearchView){
|
||||||
|
|
||||||
val queryList = mutableListOf<String>()
|
queryList = mutableListOf()
|
||||||
if (queriesChipGroup!!.childCount > 0){
|
if (queriesChipGroup!!.childCount > 0){
|
||||||
queriesChipGroup!!.children.forEach {
|
queriesChipGroup!!.children.forEach {
|
||||||
val query = (it as Chip).text.toString().trim {it2 -> it2 <= ' '}
|
val query = (it as Chip).text.toString().trim {it2 -> it2 <= ' '}
|
||||||
|
|
@ -689,7 +710,8 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
private fun showSingleDownloadSheet(
|
private fun showSingleDownloadSheet(
|
||||||
resultItem: ResultItem,
|
resultItem: ResultItem,
|
||||||
type: DownloadViewModel.Type
|
type: DownloadViewModel.Type,
|
||||||
|
disableUpdateData : Boolean = false
|
||||||
){
|
){
|
||||||
if(findNavController().currentBackStack.value.firstOrNull {it.destination.id == R.id.downloadBottomSheetDialog} == null &&
|
if(findNavController().currentBackStack.value.firstOrNull {it.destination.id == R.id.downloadBottomSheetDialog} == null &&
|
||||||
findNavController().currentDestination?.id == R.id.homeFragment
|
findNavController().currentDestination?.id == R.id.homeFragment
|
||||||
|
|
@ -698,6 +720,9 @@ class HomeFragment : Fragment(), HomeAdapter.OnItemClickListener, SearchSuggesti
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
bundle.putParcelable("result", resultItem)
|
bundle.putParcelable("result", resultItem)
|
||||||
bundle.putSerializable("type", downloadViewModel.getDownloadType(type, resultItem.url))
|
bundle.putSerializable("type", downloadViewModel.getDownloadType(type, resultItem.url))
|
||||||
|
if (disableUpdateData) {
|
||||||
|
bundle.putBoolean("disableUpdateData", true)
|
||||||
|
}
|
||||||
findNavController().navigate(R.id.downloadBottomSheetDialog, bundle)
|
findNavController().navigate(R.id.downloadBottomSheetDialog, bundle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,10 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
||||||
progressBar.progress = 0
|
progressBar.progress = 0
|
||||||
progressBar.isIndeterminate = true
|
progressBar.isIndeterminate = true
|
||||||
|
|
||||||
|
//OUTPUT ------------------------------------------------------------
|
||||||
|
val output = card.findViewById<TextView>(R.id.output)
|
||||||
|
output.tag = "${item.id}##output"
|
||||||
|
|
||||||
// TITLE ----------------------------------
|
// TITLE ----------------------------------
|
||||||
val itemTitle = card.findViewById<TextView>(R.id.title)
|
val itemTitle = card.findViewById<TextView>(R.id.title)
|
||||||
var title = item.title.ifEmpty { item.playlistTitle.ifEmpty { item.url } }
|
var title = item.title.ifEmpty { item.playlistTitle.ifEmpty { item.url } }
|
||||||
|
|
@ -131,8 +135,8 @@ class ActiveDownloadMinifiedAdapter(onItemClickListener: OnItemClickListener, ac
|
||||||
popup.menuInflater.inflate(R.menu.active_downloads_minified, popup.menu)
|
popup.menuInflater.inflate(R.menu.active_downloads_minified, popup.menu)
|
||||||
if (Build.VERSION.SDK_INT > 27) popup.menu.setGroupDividerEnabled(true)
|
if (Build.VERSION.SDK_INT > 27) popup.menu.setGroupDividerEnabled(true)
|
||||||
|
|
||||||
val pause = popup.menu[0]
|
// val pause = popup.menu[0]
|
||||||
val resume = popup.menu[1]
|
// val resume = popup.menu[1]
|
||||||
//
|
//
|
||||||
// if (paused){
|
// if (paused){
|
||||||
// pause.isVisible = false
|
// pause.isVisible = false
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
private lateinit var result: ResultItem
|
private lateinit var result: ResultItem
|
||||||
private lateinit var type: Type
|
private lateinit var type: Type
|
||||||
|
private var disableUpdateData : Boolean = false
|
||||||
private var currentDownloadItem: DownloadItem? = null
|
private var currentDownloadItem: DownloadItem? = null
|
||||||
private var incognito: Boolean = false
|
private var incognito: Boolean = false
|
||||||
|
|
||||||
|
|
@ -108,6 +109,7 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
dwl = arguments?.getParcelable<DownloadItem>("downloadItem")
|
dwl = arguments?.getParcelable<DownloadItem>("downloadItem")
|
||||||
}
|
}
|
||||||
type = arguments?.getSerializable("type") as Type
|
type = arguments?.getSerializable("type") as Type
|
||||||
|
disableUpdateData = arguments?.getBoolean("disableUpdateData") == true
|
||||||
|
|
||||||
if (res == null){
|
if (res == null){
|
||||||
dismiss()
|
dismiss()
|
||||||
|
|
@ -429,13 +431,11 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//if auto-update after the card is open is off
|
//if auto-update after the card is open is off
|
||||||
if (result.title.isEmpty() && currentDownloadItem == null) {
|
if (result.title.isEmpty() && currentDownloadItem == null && sharedPreferences.getBoolean("quick_download", false)) {
|
||||||
if(sharedPreferences.getBoolean("quick_download", false)) {
|
(updateItem.parent as LinearLayout).visibility = View.VISIBLE
|
||||||
(updateItem.parent as LinearLayout).visibility = View.VISIBLE
|
updateItem.setOnClickListener {
|
||||||
updateItem.setOnClickListener {
|
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||||
(updateItem.parent as LinearLayout).visibility = View.GONE
|
initUpdateData()
|
||||||
initUpdateData()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
(updateItem.parent as LinearLayout).visibility = View.GONE
|
(updateItem.parent as LinearLayout).visibility = View.GONE
|
||||||
|
|
@ -463,24 +463,28 @@ class DownloadBottomSheetDialog : BottomSheetDialogFragment() {
|
||||||
|
|
||||||
|
|
||||||
//update in the background if there is no data
|
//update in the background if there is no data
|
||||||
if(result.title.isEmpty() && currentDownloadItem == null && !sharedPreferences.getBoolean("quick_download", false) && type != Type.command){
|
if (!disableUpdateData) {
|
||||||
initUpdateData()
|
if(result.title.isEmpty() && currentDownloadItem == null && !sharedPreferences.getBoolean("quick_download", false) && type != Type.command){
|
||||||
}else {
|
initUpdateData()
|
||||||
val usingGenericFormatsOrEmpty = result.formats.isEmpty() || result.formats.any { it.format_note.contains("ytdlnisgeneric") }
|
}else {
|
||||||
if (usingGenericFormatsOrEmpty && sharedPreferences.getBoolean("update_formats", false) && !sharedPreferences.getBoolean("quick_download", false)){
|
val usingGenericFormatsOrEmpty = result.formats.isEmpty() || result.formats.any { it.format_note.contains("ytdlnisgeneric") }
|
||||||
initUpdateFormats(result)
|
if (usingGenericFormatsOrEmpty && sharedPreferences.getBoolean("update_formats", false) && !sharedPreferences.getBoolean("quick_download", false)){
|
||||||
|
initUpdateFormats(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
resultViewModel.uiState.collectLatest { res ->
|
resultViewModel.uiState.collectLatest { res ->
|
||||||
if (res.errorMessage != null){
|
if (res.errorMessage != null){
|
||||||
kotlin.runCatching { UiUtil.handleResultResponse(requireActivity(), res, closed = {
|
kotlin.runCatching { UiUtil.handleNoResults(requireActivity(), res.errorMessage!!, true, continued = {}, closed = {
|
||||||
dismiss()
|
dismiss()
|
||||||
}) }
|
}) }
|
||||||
resultViewModel.uiState.update {it.copy(errorMessage = null, actions = null) }
|
resultViewModel.uiState.update {it.copy(errorMessage = null) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -774,6 +774,7 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
val fileSizes = mutableListOf<Long>()
|
val fileSizes = mutableListOf<Long>()
|
||||||
items.forEach {
|
items.forEach {
|
||||||
if (it.type == DownloadViewModel.Type.video){
|
if (it.type == DownloadViewModel.Type.video){
|
||||||
|
println(it.format.filesize)
|
||||||
if (it.format.filesize <= 5L) {
|
if (it.format.filesize <= 5L) {
|
||||||
fileSizes.add(0)
|
fileSizes.add(0)
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -787,6 +788,8 @@ class DownloadMultipleBottomSheetDialog : BottomSheetDialogFragment(), Configure
|
||||||
}
|
}
|
||||||
fileSizes.add(it.format.filesize + audioFormatSize)
|
fileSizes.add(it.format.filesize + audioFormatSize)
|
||||||
}
|
}
|
||||||
|
}else if (it.type == DownloadViewModel.Type.audio){
|
||||||
|
fileSizes.add(it.format.filesize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ class FormatSelectionBottomSheetDialog(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
items = _items.distinctBy { it!!.url }.toMutableList()
|
items = _items.toMutableList()
|
||||||
if (items.size == 1) {
|
if (items.size == 1) {
|
||||||
formats = items.first()!!.allFormats
|
formats = items.first()!!.allFormats
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -192,8 +192,10 @@ class FormatSelectionBottomSheetDialog(
|
||||||
|
|
||||||
refreshBtn.setOnClickListener {
|
refreshBtn.setOnClickListener {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val itemsThatHaveFormats = items.filter { it!!.allFormats.isNotEmpty() }
|
val distinctItems = items.distinctBy { it!!.url }
|
||||||
val itemsWithMissingFormats = items.filter { it!!.allFormats.isEmpty() }.ifEmpty { items }
|
|
||||||
|
val itemsThatHaveFormats = distinctItems.filter { it!!.allFormats.isNotEmpty() }
|
||||||
|
val itemsWithMissingFormats = distinctItems.filter { it!!.allFormats.isEmpty() }.ifEmpty { distinctItems }
|
||||||
|
|
||||||
if (itemsWithMissingFormats.size > 10){
|
if (itemsWithMissingFormats.size > 10){
|
||||||
continueInBackgroundSnackBar = Snackbar.make(view, R.string.update_formats_background, Snackbar.LENGTH_LONG)
|
continueInBackgroundSnackBar = Snackbar.make(view, R.string.update_formats_background, Snackbar.LENGTH_LONG)
|
||||||
|
|
@ -238,11 +240,7 @@ class FormatSelectionBottomSheetDialog(
|
||||||
}
|
}
|
||||||
}.onFailure { err ->
|
}.onFailure { err ->
|
||||||
withContext(Dispatchers.Main){
|
withContext(Dispatchers.Main){
|
||||||
UiUtil.handleResultResponse(requireActivity(), ResultViewModel.ResultsUiState(
|
UiUtil.handleNoResults(requireActivity(), err.message.toString(), false, continued = {}, closed = {})
|
||||||
false,
|
|
||||||
Pair(R.string.no_results, err.message.toString()),
|
|
||||||
mutableListOf(Pair(R.string.copy_log, ResultViewModel.ResultAction.COPY_LOG))
|
|
||||||
), closed = {})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,9 +268,9 @@ class FormatSelectionBottomSheetDialog(
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
multipleFormatsListener.onFormatUpdated(it.url, it.formats)
|
multipleFormatsListener.onFormatUpdated(it.url, it.formats)
|
||||||
items.firstOrNull { item -> item!!.url == it.url }?.apply {
|
items.filter { item -> item!!.url == it.url }.forEach { d ->
|
||||||
allFormats.clear()
|
d?.allFormats?.clear()
|
||||||
allFormats.addAll(it.formats)
|
d?.allFormats?.addAll(it.formats)
|
||||||
}
|
}
|
||||||
progressInt++
|
progressInt++
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
|
@ -290,7 +288,7 @@ class FormatSelectionBottomSheetDialog(
|
||||||
val flatFormatCollection = formatCollection.flatten()
|
val flatFormatCollection = formatCollection.flatten()
|
||||||
val commonFormats =
|
val commonFormats =
|
||||||
flatFormatCollection.groupingBy { it.format_id }.eachCount()
|
flatFormatCollection.groupingBy { it.format_id }.eachCount()
|
||||||
.filter { it.value == items.size }
|
.filter { it.value == distinctItems.size }
|
||||||
.mapValues { flatFormatCollection.first { f -> f.format_id == it.key } }
|
.mapValues { flatFormatCollection.first { f -> f.format_id == it.key } }
|
||||||
.map { it.value }
|
.map { it.value }
|
||||||
formats.addAll(commonFormats)
|
formats.addAll(commonFormats)
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ import com.deniscerri.ytdl.util.InfoUtil
|
||||||
import com.deniscerri.ytdl.util.NotificationUtil
|
import com.deniscerri.ytdl.util.NotificationUtil
|
||||||
import com.deniscerri.ytdl.util.UiUtil
|
import com.deniscerri.ytdl.util.UiUtil
|
||||||
import com.deniscerri.ytdl.util.VideoPlayerUtil
|
import com.deniscerri.ytdl.util.VideoPlayerUtil
|
||||||
|
import com.deniscerri.ytdl.work.DownloadWorker
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
|
|
@ -72,6 +73,9 @@ import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.greenrobot.eventbus.Subscribe
|
||||||
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
@ -86,8 +90,7 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
||||||
|
|
||||||
private lateinit var activeAdapter: ActiveDownloadMinifiedAdapter
|
private lateinit var activeAdapter: ActiveDownloadMinifiedAdapter
|
||||||
private lateinit var queuedAdapter: GenericDownloadAdapter
|
private lateinit var queuedAdapter: GenericDownloadAdapter
|
||||||
private var activeCount: Int = 0
|
|
||||||
|
|
||||||
private lateinit var downloadManager: DownloadManager
|
private lateinit var downloadManager: DownloadManager
|
||||||
|
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
|
@ -97,6 +100,7 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
infoUtil = InfoUtil(requireActivity())
|
infoUtil = InfoUtil(requireActivity())
|
||||||
|
notificationUtil = NotificationUtil(requireActivity())
|
||||||
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
downloadViewModel = ViewModelProvider(this)[DownloadViewModel::class.java]
|
||||||
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
|
||||||
downloadManager = requireContext().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
downloadManager = requireContext().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
|
||||||
|
|
@ -237,12 +241,6 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
downloadViewModel.activeDownloadsCount.collectLatest {
|
|
||||||
activeCount = it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bottomSheetLink.text = item.url
|
bottomSheetLink.text = item.url
|
||||||
bottomSheetLink.setOnClickListener{
|
bottomSheetLink.setOnClickListener{
|
||||||
|
|
@ -482,21 +480,42 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
||||||
|
|
||||||
override fun onCancelClick(itemID: Long) {
|
override fun onCancelClick(itemID: Long) {
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
if (activeCount == 1){
|
YoutubeDL.getInstance().destroyProcessById(itemID.toString())
|
||||||
val queue = withContext(Dispatchers.IO){
|
notificationUtil.cancelDownloadNotification(itemID.toInt())
|
||||||
val list = downloadViewModel.getQueued().toMutableList()
|
|
||||||
list.map { it.status = DownloadRepository.Status.Queued.toString() }
|
|
||||||
list
|
|
||||||
}
|
|
||||||
|
|
||||||
runBlocking {
|
val item = withContext(Dispatchers.IO){
|
||||||
downloadViewModel.queueDownloads(queue)
|
downloadViewModel.getItemByID(itemID)
|
||||||
|
}
|
||||||
|
item.status = DownloadRepository.Status.Cancelled.toString()
|
||||||
|
withContext(Dispatchers.IO){
|
||||||
|
downloadViewModel.updateDownload(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
val activeCount = withContext(Dispatchers.IO){
|
||||||
|
downloadViewModel.getActiveDownloadsCount()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeCount == 0){
|
||||||
|
val queuedCount = withContext(Dispatchers.IO){
|
||||||
|
downloadViewModel.getQueuedDownloadsCount()
|
||||||
|
}
|
||||||
|
if (queuedCount == 0) {
|
||||||
|
sharedPreferences.edit().putBoolean("paused_downloads", false).apply()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
if (activeCount == 1){
|
||||||
|
val queue = withContext(Dispatchers.IO){
|
||||||
|
downloadViewModel.getQueued()
|
||||||
|
}
|
||||||
|
|
||||||
cancelActiveDownload(itemID)
|
if (!sharedPreferences.getBoolean("paused_downloads", false)){
|
||||||
|
runBlocking {
|
||||||
|
downloadViewModel.queueDownloads(queue)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
override fun onCardClick() {
|
override fun onCardClick() {
|
||||||
this.dismiss()
|
this.dismiss()
|
||||||
|
|
@ -505,22 +524,29 @@ class ResultCardDetailsDialog : BottomSheetDialogFragment(), GenericDownloadAdap
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun cancelActiveDownload(itemID: Long){
|
//dont remove
|
||||||
lifecycleScope.launch {
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
val id = itemID.toInt()
|
fun onDownloadProgressEvent(event: DownloadWorker.WorkerProgress) {
|
||||||
YoutubeDL.getInstance().destroyProcessById(id.toString())
|
val progressBar = requireView().findViewWithTag<LinearProgressIndicator>("${event.downloadItemID}##progress")
|
||||||
notificationUtil.cancelDownloadNotification(id)
|
val outputText = requireView().findViewWithTag<TextView>("${event.downloadItemID}##output")
|
||||||
|
|
||||||
withContext(Dispatchers.IO){
|
requireActivity().runOnUiThread {
|
||||||
downloadViewModel.getItemByID(itemID)
|
try {
|
||||||
}.let {
|
progressBar?.setProgressCompat(event.progress, true)
|
||||||
it.status = DownloadRepository.Status.Cancelled.toString()
|
outputText?.text = event.output
|
||||||
lifecycleScope.launch(Dispatchers.IO){
|
}catch (ignored: Exception) {}
|
||||||
downloadViewModel.updateDownload(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
EventBus.getDefault().register(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
EventBus.getDefault().unregister(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,9 @@ class DownloadLogFragment : Fragment() {
|
||||||
private lateinit var logViewModel: LogViewModel
|
private lateinit var logViewModel: LogViewModel
|
||||||
private lateinit var sharedPreferences: SharedPreferences
|
private lateinit var sharedPreferences: SharedPreferences
|
||||||
|
|
||||||
|
private var autoScroll : Boolean = true
|
||||||
|
private var scrollDownBtn : MenuItem? = null
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
|
|
@ -113,6 +116,7 @@ class DownloadLogFragment : Fragment() {
|
||||||
|
|
||||||
contentScrollView.enableFastScroll()
|
contentScrollView.enableFastScroll()
|
||||||
|
|
||||||
|
scrollDownBtn = bottomAppBar?.menu?.children?.first { it.itemId == R.id.scroll_down }
|
||||||
|
|
||||||
val slider = view.findViewById<Slider>(R.id.textsize_seekbar)
|
val slider = view.findViewById<Slider>(R.id.textsize_seekbar)
|
||||||
bottomAppBar?.setOnMenuItemClickListener { m: MenuItem ->
|
bottomAppBar?.setOnMenuItemClickListener { m: MenuItem ->
|
||||||
|
|
@ -124,16 +128,17 @@ class DownloadLogFragment : Fragment() {
|
||||||
scrollView.removeAllViews()
|
scrollView.removeAllViews()
|
||||||
parent.removeView(scrollView)
|
parent.removeView(scrollView)
|
||||||
parent.addView(content, 0)
|
parent.addView(content, 0)
|
||||||
contentScrollView.setPadding(0,0,0,
|
// contentScrollView.setPadding(0,0,0,
|
||||||
(requireContext().resources.displayMetrics.density * 150).toInt()
|
// (requireContext().resources.displayMetrics.density * 150).toInt()
|
||||||
)
|
// )
|
||||||
|
updateAutoScrollState()
|
||||||
}else{
|
}else{
|
||||||
val parent = content.parent as ViewGroup
|
val parent = content.parent as ViewGroup
|
||||||
parent.removeView(content)
|
parent.removeView(content)
|
||||||
scrollView = HorizontalScrollView(requireContext())
|
scrollView = HorizontalScrollView(requireContext())
|
||||||
scrollView.setPadding(0,0,0,
|
// scrollView.setPadding(0,0,0,
|
||||||
(requireContext().resources.displayMetrics.density * 150).toInt()
|
// (requireContext().resources.displayMetrics.density * 150).toInt()
|
||||||
)
|
// )
|
||||||
contentScrollView.setPadding(0,0,0,0)
|
contentScrollView.setPadding(0,0,0,0)
|
||||||
scrollView.layoutParams = LinearLayout.LayoutParams(
|
scrollView.layoutParams = LinearLayout.LayoutParams(
|
||||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||||
|
|
@ -142,11 +147,13 @@ class DownloadLogFragment : Fragment() {
|
||||||
scrollView.addView(content)
|
scrollView.addView(content)
|
||||||
scrollView.id = R.id.horizontalscroll_output
|
scrollView.id = R.id.horizontalscroll_output
|
||||||
parent.addView(scrollView, 0)
|
parent.addView(scrollView, 0)
|
||||||
|
updateAutoScrollState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
R.id.scroll_down -> {
|
R.id.scroll_down -> {
|
||||||
m.isVisible = false
|
m.isVisible = false
|
||||||
|
autoScroll = true
|
||||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,9 +178,12 @@ class DownloadLogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
contentScrollView.setOnScrollChangeListener { view, sx, sy, osx, osy ->
|
contentScrollView.setOnScrollChangeListener { view, sx, sy, osx, osy ->
|
||||||
if (sy < osy){
|
updateAutoScrollState()
|
||||||
bottomAppBar?.menu?.get(1)?.isVisible = contentScrollView.canScrollVertically(1)
|
}
|
||||||
}
|
|
||||||
|
contentScrollView.setOnTouchListener { view, motionEvent ->
|
||||||
|
autoScroll = false
|
||||||
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -185,9 +195,11 @@ class DownloadLogFragment : Fragment() {
|
||||||
content.setText(logItem.content, TextView.BufferType.SPANNABLE)
|
content.setText(logItem.content, TextView.BufferType.SPANNABLE)
|
||||||
bottomAppBar?.menu?.get(1)?.isVisible = contentScrollView.canScrollVertically(1)
|
bottomAppBar?.menu?.get(1)?.isVisible = contentScrollView.canScrollVertically(1)
|
||||||
}
|
}
|
||||||
if (!bottomAppBar.menu.children.first { it.itemId == R.id.scroll_down }.isVisible){
|
if (autoScroll){
|
||||||
content.scrollTo(0, content.height)
|
//content.scrollTo(0, content.height)
|
||||||
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
content.post {
|
||||||
|
contentScrollView.fullScroll(View.FOCUS_DOWN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -195,6 +207,11 @@ class DownloadLogFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateAutoScrollState() {
|
||||||
|
val canVerticallyScroll = contentScrollView.canScrollVertically(1)
|
||||||
|
scrollDownBtn?.isVisible = canVerticallyScroll
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "DownloadLogActivity"
|
private const val TAG = "DownloadLogActivity"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,8 +81,7 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
editor.putString("command_path", FileUtil.getDefaultCommandPath())
|
editor.putString("command_path", FileUtil.getDefaultCommandPath())
|
||||||
}
|
}
|
||||||
|
|
||||||
if((VERSION.SDK_INT >= 30 && Environment.isExternalStorageManager()) ||
|
if (FileUtil.hasAllFilesAccess()) {
|
||||||
VERSION.SDK_INT < 30) {
|
|
||||||
accessAllFiles!!.isVisible = false
|
accessAllFiles!!.isVisible = false
|
||||||
cacheDownloads!!.isEnabled = true
|
cacheDownloads!!.isEnabled = true
|
||||||
}else{
|
}else{
|
||||||
|
|
@ -90,8 +89,6 @@ class FolderSettingsFragment : BaseSettingsFragment() {
|
||||||
cacheDownloads!!.isEnabled = false
|
cacheDownloads!!.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.apply()
|
|
||||||
|
|
||||||
musicPath!!.summary = FileUtil.formatPath(preferences.getString("music_path", "")!!)
|
musicPath!!.summary = FileUtil.formatPath(preferences.getString("music_path", "")!!)
|
||||||
musicPath!!.onPreferenceClickListener =
|
musicPath!!.onPreferenceClickListener =
|
||||||
Preference.OnPreferenceClickListener {
|
Preference.OnPreferenceClickListener {
|
||||||
|
|
|
||||||
|
|
@ -261,20 +261,27 @@ object Extensions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fun String.appendLineToLog(line: String): String {
|
fun String.appendLineToLog(line: String = ""): String {
|
||||||
// val lines = this.split("\n")
|
val lines = this.lines().toMutableList()
|
||||||
// if (!lines.takeLast(3).contains(line)){
|
val finishingProgressLinesRegex = Pattern.compile("\\[download]\\h+(100%|[a-zA-Z])")
|
||||||
// //clean dublicate progress + add newline
|
|
||||||
// var newLine = line
|
if (line.isNotBlank()) {
|
||||||
// if (newLine.contains("[download")) {
|
var newLine = ""
|
||||||
// newLine = "[download]" + line.split("[download]").last()
|
val newLines = line.lines()
|
||||||
// }
|
if (!lines.takeLast(3).any { newLines.contains(it) }) {
|
||||||
//
|
lines.addAll(newLines.dropLast(1))
|
||||||
// return lines.dropLastWhile { it.contains("[download") }.joinToString("\n") + "\n${newLine}"
|
newLine = "\n${newLines.last()}"
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// return this
|
return lines.dropLastWhile {
|
||||||
// }
|
it.contains("[download") && !finishingProgressLinesRegex.matcher(it).find()
|
||||||
|
}.joinToString("\n") + newLine
|
||||||
|
}
|
||||||
|
|
||||||
|
return lines.filterNot {
|
||||||
|
it.contains("[download") && !finishingProgressLinesRegex.matcher(it).find()
|
||||||
|
}.joinToString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
fun ImageView.loadThumbnail(hideThumb: Boolean, imageURL: String){
|
fun ImageView.loadThumbnail(hideThumb: Boolean, imageURL: String){
|
||||||
if(!hideThumb){
|
if(!hideThumb){
|
||||||
|
|
|
||||||
|
|
@ -400,4 +400,9 @@ object FileUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun hasAllFilesAccess() : Boolean {
|
||||||
|
if (Build.VERSION.SDK_INT < 30) return true
|
||||||
|
return Environment.isExternalStorageManager()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -4,7 +4,6 @@ import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
import android.content.res.Resources.NotFoundException
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.text.Html
|
import android.text.Html
|
||||||
|
|
@ -43,7 +42,6 @@ import java.lang.reflect.Type
|
||||||
import java.net.HttpURLConnection
|
import java.net.HttpURLConnection
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
|
|
||||||
class InfoUtil(private val context: Context) {
|
class InfoUtil(private val context: Context) {
|
||||||
|
|
@ -168,6 +166,13 @@ class InfoUtil(private val context: Context) {
|
||||||
fun getYoutubeVideo(url: String): List<ResultItem>? {
|
fun getYoutubeVideo(url: String): List<ResultItem>? {
|
||||||
val theURL = url.replace("\\?list.*".toRegex(), "")
|
val theURL = url.replace("\\?list.*".toRegex(), "")
|
||||||
try{
|
try{
|
||||||
|
//TODO NEWPIPE TEST
|
||||||
|
// val extractor = ServiceList.YouTube.getStreamExtractor(url)
|
||||||
|
// extractor.fetchPage()
|
||||||
|
// val extractor2 = ServiceList.YouTube.getPlaylistExtractor(url)
|
||||||
|
// extractor2.fetchPage()
|
||||||
|
// var info = extractor2.getPage(extractor2.initialPage.nextPage)
|
||||||
|
|
||||||
val id = getIDFromYoutubeURL(theURL)
|
val id = getIDFromYoutubeURL(theURL)
|
||||||
val res = genericRequest("$pipedURL/streams/$id")
|
val res = genericRequest("$pipedURL/streams/$id")
|
||||||
if (res.length() == 0) {
|
if (res.length() == 0) {
|
||||||
|
|
@ -678,7 +683,7 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
val lang = sharedPreferences.getString("app_language", "en")
|
val lang = sharedPreferences.getString("app_language", "en")
|
||||||
if (searchEngine == "ytsearch" || query.isYoutubeURL()) {
|
if (searchEngine == "ytsearch" || query.isYoutubeURL()) {
|
||||||
var extractorArgs = "player_client=default,mediaconnect,android"
|
var extractorArgs = "player_client=default,mediaconnect"
|
||||||
if (context.getStringArray(R.array.subtitle_langs).contains(lang)) {
|
if (context.getStringArray(R.array.subtitle_langs).contains(lang)) {
|
||||||
extractorArgs += ";lang=$lang"
|
extractorArgs += ";lang=$lang"
|
||||||
}
|
}
|
||||||
|
|
@ -1034,6 +1039,12 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun MutableList<String>.addOption(vararg options: String) {
|
||||||
|
options.forEach {
|
||||||
|
this.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("RestrictedApi")
|
@SuppressLint("RestrictedApi")
|
||||||
fun buildYoutubeDLRequest(downloadItem: DownloadItem) : YoutubeDLRequest {
|
fun buildYoutubeDLRequest(downloadItem: DownloadItem) : YoutubeDLRequest {
|
||||||
|
|
@ -1052,14 +1063,16 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val metadataCommands = mutableListOf<String>()
|
||||||
|
|
||||||
if (downloadItem.playlistIndex != null && useItemURL) {
|
if (downloadItem.playlistIndex != null && useItemURL) {
|
||||||
request.addOption("--parse-metadata", " ${downloadItem.playlistIndex}: %(playlist_index)s")
|
metadataCommands.addOption("--parse-metadata", " ${downloadItem.playlistIndex}: %(playlist_index)s")
|
||||||
}
|
}
|
||||||
|
|
||||||
val type = downloadItem.type
|
val type = downloadItem.type
|
||||||
|
|
||||||
val downDir : File
|
val downDir : File
|
||||||
val canWrite = File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite() || sharedPreferences.getBoolean("access_all_files", false)
|
val canWrite = File(FileUtil.formatPath(downloadItem.downloadPath)).canWrite()
|
||||||
if (!sharedPreferences.getBoolean("cache_downloads", true) && canWrite){
|
if (!sharedPreferences.getBoolean("cache_downloads", true) && canWrite){
|
||||||
downDir = File(FileUtil.formatPath(downloadItem.downloadPath))
|
downDir = File(FileUtil.formatPath(downloadItem.downloadPath))
|
||||||
request.addOption("--no-quiet")
|
request.addOption("--no-quiet")
|
||||||
|
|
@ -1162,18 +1175,14 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(downloadItem.title.isNotBlank()){
|
if(downloadItem.title.isNotBlank()){
|
||||||
request.addCommands(listOf("--replace-in-metadata", "video:title", ".+", downloadItem.title.take(180)))
|
metadataCommands.addOption("--replace-in-metadata", "title", ".+", downloadItem.title.take(180))
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(title)s:%(meta_title)s")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (downloadItem.author.isNotBlank()){
|
if (downloadItem.author.isNotBlank()){
|
||||||
request.addCommands(listOf("--replace-in-metadata", "video:uploader", ".+", downloadItem.author.take(30)))
|
metadataCommands.addOption("--replace-in-metadata", "uploader", ".+", downloadItem.author.take(30))
|
||||||
}
|
metadataCommands.addOption("--parse-metadata", "%(uploader)s:%(artist)s")
|
||||||
|
|
||||||
request.addOption("--parse-metadata", "uploader:^(?P<uploader>.*?)(?:(?= - Topic)|$)")
|
|
||||||
|
|
||||||
if (embedMetadata){
|
|
||||||
request.addOption("--parse-metadata", "%(uploader,channel,creator,artist|null)s:%(uploader)s")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadItem.downloadSections.isNotBlank()){
|
if (downloadItem.downloadSections.isNotBlank()){
|
||||||
|
|
@ -1196,7 +1205,7 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("use_audio_quality", false)){
|
if (sharedPreferences.getBoolean("use_audio_quality", false)){
|
||||||
request.addOption("--audio-quality", sharedPreferences.getInt("audio_quality", 0))
|
request.addOption("--audio-quality", sharedPreferences.getInt("audio_quality", 0).toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedPreferences.getBoolean("write_description", false)){
|
if (sharedPreferences.getBoolean("write_description", false)){
|
||||||
|
|
@ -1204,7 +1213,7 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downloadItem.url.isYoutubeURL()) {
|
if (downloadItem.url.isYoutubeURL()) {
|
||||||
var extractorArgs = "player_client=default,mediaconnect,android"
|
var extractorArgs = "player_client=default,mediaconnect"
|
||||||
val lang = sharedPreferences.getString("app_language", "en")
|
val lang = sharedPreferences.getString("app_language", "en")
|
||||||
if (context.getStringArray(R.array.subtitle_langs).contains(lang)) {
|
if (context.getStringArray(R.array.subtitle_langs).contains(lang)) {
|
||||||
extractorArgs += ";lang=$lang"
|
extractorArgs += ";lang=$lang"
|
||||||
|
|
@ -1261,7 +1270,7 @@ class InfoUtil(private val context: Context) {
|
||||||
}
|
}
|
||||||
request.addOption("-x")
|
request.addOption("-x")
|
||||||
|
|
||||||
val formatSorting = StringBuilder("hasaud")
|
val formatSorting = StringBuilder("hasaud,size")
|
||||||
|
|
||||||
if (aCodecPref.isNotBlank()){
|
if (aCodecPref.isNotBlank()){
|
||||||
formatSorting.append(",acodec:$aCodecPref")
|
formatSorting.append(",acodec:$aCodecPref")
|
||||||
|
|
@ -1285,31 +1294,46 @@ class InfoUtil(private val context: Context) {
|
||||||
request.addOption("-P", downDir.absolutePath)
|
request.addOption("-P", downDir.absolutePath)
|
||||||
request.addOption("-S", formatSorting.toString())
|
request.addOption("-S", formatSorting.toString())
|
||||||
|
|
||||||
|
metadataCommands.addOption("--parse-metadata", """%(uploader,artist,channel,creator|null)s:^(?P<uploader>.*?)(?:(?= - Topic)|$)""")
|
||||||
|
|
||||||
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
if (downloadItem.audioPreferences.splitByChapters && downloadItem.downloadSections.isBlank()){
|
||||||
request.addOption("--split-chapters")
|
request.addOption("--split-chapters")
|
||||||
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
request.addOption("-o", "chapter:%(section_title)s.%(ext)s")
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
if (embedMetadata){
|
if (embedMetadata){
|
||||||
request.addOption("--embed-metadata")
|
metadataCommands.addOption("--embed-metadata")
|
||||||
request.addOption("--parse-metadata", "%(artist,uploader|)s:^(?P<meta_album_artist>[^,]*)")
|
|
||||||
request.addOption("--parse-metadata", "%(album_artist,meta_album_artist|)s:%(album_artist)s")
|
|
||||||
|
|
||||||
request.addOption("--parse-metadata", "description:(?:Released on: )(?P<dscrptn_year>\\d{4})")
|
val emptyAuthor = downloadItem.author.isEmpty()
|
||||||
request.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P<meta_date>\\d+)")
|
val usePlaylistMetadata = sharedPreferences.getBoolean("playlist_as_album", true)
|
||||||
|
|
||||||
if (downloadItem.playlistTitle.isNotEmpty()) {
|
if (emptyAuthor) {
|
||||||
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
|
if (usePlaylistMetadata) {
|
||||||
request.addOption("--parse-metadata", "%(track_number,playlist_index)d:(?P<track_number>\\d+)")
|
metadataCommands.addOption("--parse-metadata", "%(playlist_uploader,artist,uploader|)s:^(?P<first_artist>.*?)(?:(?=,\\s+)|$)")
|
||||||
} else {
|
}else{
|
||||||
request.addOption("--parse-metadata", "%(album,title)s:%(meta_album)s")
|
metadataCommands.addOption("--parse-metadata", "%(artist,uploader|)s:^(?P<first_artist>.*?)(?:(?=,\\s+)|$)")
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (usePlaylistMetadata) {
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(playlist_uploader,artist|)s:^(?P<first_artist>.*?)(?:(?=,\\s+)|$)")
|
||||||
|
}else{
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(artist|)s:^(?P<first_artist>.*?)(?:(?=,\\s+)|$)")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
metadataCommands.addOption("--parse-metadata", "description:(?:Released on: )(?P<dscrptn_year>\\d{4})")
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(dscrptn_year,release_year,release_date>%Y,upload_date>%Y)s:(?P<meta_date>\\d+)")
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(album_artist,first_artist|)s:%(album_artist)s")
|
||||||
|
metadataCommands.addOption("--parse-metadata", "%(track_number,playlist_index)d:(?P<track_number>\\d+)")
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val cropThumb = downloadItem.audioPreferences.cropThumb ?: sharedPreferences.getBoolean("crop_thumbnail", true)
|
val cropThumb = downloadItem.audioPreferences.cropThumb ?: sharedPreferences.getBoolean("crop_thumbnail", true)
|
||||||
if (downloadItem.audioPreferences.embedThumb){
|
if (downloadItem.audioPreferences.embedThumb){
|
||||||
request.addOption("--embed-thumbnail")
|
metadataCommands.addOption("--embed-thumbnail")
|
||||||
if (!request.hasOption("--convert-thumbnails")) request.addOption("--convert-thumbnails", thumbnailFormat!!)
|
if (!request.hasOption("--convert-thumbnails")) metadataCommands.addOption("--convert-thumbnails", thumbnailFormat!!)
|
||||||
|
|
||||||
val thumbnailConfig = StringBuilder("")
|
val thumbnailConfig = StringBuilder("")
|
||||||
val cropConfig = """-vf crop=\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\"""""
|
val cropConfig = """-vf crop=\"'if(gt(ih,iw),iw,ih)':'if(gt(iw,ih),ih,iw)'\"""""
|
||||||
|
|
@ -1326,7 +1350,7 @@ class InfoUtil(private val context: Context) {
|
||||||
runCatching {
|
runCatching {
|
||||||
val config = File(context.cacheDir.absolutePath + "/config" + downloadItem.id + "##ffmpegCrop.txt")
|
val config = File(context.cacheDir.absolutePath + "/config" + downloadItem.id + "##ffmpegCrop.txt")
|
||||||
config.writeText(thumbnailConfig.toString())
|
config.writeText(thumbnailConfig.toString())
|
||||||
request.addOption("--config", config.absolutePath)
|
metadataCommands.addOption("--config", config.absolutePath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1339,6 +1363,8 @@ class InfoUtil(private val context: Context) {
|
||||||
|
|
||||||
}
|
}
|
||||||
DownloadViewModel.Type.video -> {
|
DownloadViewModel.Type.video -> {
|
||||||
|
metadataCommands.addOption("--parse-metadata", """%(uploader,channel,creator,artist|null)s:^(?P<uploader>.*?)(?:(?= - Topic)|$)""")
|
||||||
|
|
||||||
val supportedContainers = context.resources.getStringArray(R.array.video_containers)
|
val supportedContainers = context.resources.getStringArray(R.array.video_containers)
|
||||||
|
|
||||||
if (downloadItem.videoPreferences.addChapters) {
|
if (downloadItem.videoPreferences.addChapters) {
|
||||||
|
|
@ -1359,7 +1385,8 @@ class InfoUtil(private val context: Context) {
|
||||||
){
|
){
|
||||||
cont = outputContainer
|
cont = outputContainer
|
||||||
|
|
||||||
if (downloadItem.videoPreferences.recodeVideo) {
|
val cantRecode = listOf("avi")
|
||||||
|
if (downloadItem.videoPreferences.recodeVideo && !cantRecode.contains(cont)) {
|
||||||
request.addOption("--recode-video", outputContainer.lowercase())
|
request.addOption("--recode-video", outputContainer.lowercase())
|
||||||
}else{
|
}else{
|
||||||
request.addOption("--merge-output-format", outputContainer.lowercase())
|
request.addOption("--merge-output-format", outputContainer.lowercase())
|
||||||
|
|
@ -1368,7 +1395,7 @@ class InfoUtil(private val context: Context) {
|
||||||
if (!listOf("webm", "avi", "flv").contains(outputContainer.lowercase())) {
|
if (!listOf("webm", "avi", "flv").contains(outputContainer.lowercase())) {
|
||||||
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
|
||||||
if (embedThumb) {
|
if (embedThumb) {
|
||||||
request.addOption("--embed-thumbnail")
|
metadataCommands.addOption("--embed-thumbnail")
|
||||||
if (!request.hasOption("--convert-thumbnails")) request.addOption("--convert-thumbnails", thumbnailFormat!!)
|
if (!request.hasOption("--convert-thumbnails")) request.addOption("--convert-thumbnails", thumbnailFormat!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1382,7 +1409,6 @@ class InfoUtil(private val context: Context) {
|
||||||
var audioF = downloadItem.videoPreferences.audioFormatIDs.map { f ->
|
var audioF = downloadItem.videoPreferences.audioFormatIDs.map { f ->
|
||||||
val format = downloadItem.allFormats.find { it.format_id == f }
|
val format = downloadItem.allFormats.find { it.format_id == f }
|
||||||
format?.run {
|
format?.run {
|
||||||
println(format_id)
|
|
||||||
if (this.format_id.matches(".*-[0-9]+".toRegex())) {
|
if (this.format_id.matches(".*-[0-9]+".toRegex())) {
|
||||||
if (!this.lang.isNullOrBlank() && this.lang != "None") {
|
if (!this.lang.isNullOrBlank() && this.lang != "None") {
|
||||||
"ba[format_id~='^(${this.format_id.split("-")[0]})'][language^=${this.lang}]"
|
"ba[format_id~='^(${this.format_id.split("-")[0]})'][language^=${this.lang}]"
|
||||||
|
|
@ -1591,7 +1617,9 @@ class InfoUtil(private val context: Context) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (metadataCommands.isNotEmpty()){
|
||||||
|
request.addCommands(metadataCommands)
|
||||||
|
}
|
||||||
return request
|
return request
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ object NavbarUtil {
|
||||||
val pref = settings.getString("start_destination", "")!!
|
val pref = settings.getString("start_destination", "")!!
|
||||||
val items = getDefaultNavBarItems(context)
|
val items = getDefaultNavBarItems(context)
|
||||||
val navBarHasPref = getNavBarPrefs().contains(items.indexOfFirst { it.itemId == navItems[pref] }.toString())
|
val navBarHasPref = getNavBarPrefs().contains(items.indexOfFirst { it.itemId == navItems[pref] }.toString())
|
||||||
|
println("START FRAGMENT: $pref")
|
||||||
return if (pref == "") {
|
return if (pref == "") {
|
||||||
R.id.homeFragment
|
R.id.homeFragment
|
||||||
}else {
|
}else {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import androidx.core.content.FileProvider
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.documentfile.provider.DocumentFile
|
import androidx.documentfile.provider.DocumentFile
|
||||||
import androidx.navigation.NavDeepLinkBuilder
|
import androidx.navigation.NavDeepLinkBuilder
|
||||||
|
import com.deniscerri.ytdl.MainActivity
|
||||||
import com.deniscerri.ytdl.R
|
import com.deniscerri.ytdl.R
|
||||||
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
import com.deniscerri.ytdl.database.viewmodel.DownloadViewModel
|
||||||
import com.deniscerri.ytdl.receiver.CancelDownloadNotificationReceiver
|
import com.deniscerri.ytdl.receiver.CancelDownloadNotificationReceiver
|
||||||
|
|
@ -148,11 +149,9 @@ class NotificationUtil(var context: Context) {
|
||||||
fun createDownloadServiceNotification(
|
fun createDownloadServiceNotification(
|
||||||
pendingIntent: PendingIntent?,
|
pendingIntent: PendingIntent?,
|
||||||
title: String?,
|
title: String?,
|
||||||
itemID: Int,
|
|
||||||
): Notification {
|
): Notification {
|
||||||
val notificationBuilder = getBuilder(DOWNLOAD_SERVICE_CHANNEL_ID)
|
val notificationBuilder = getBuilder(DOWNLOAD_SERVICE_CHANNEL_ID)
|
||||||
|
|
||||||
|
|
||||||
return notificationBuilder
|
return notificationBuilder
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.Queue
|
import java.util.Queue
|
||||||
|
import java.util.function.Predicate
|
||||||
|
|
||||||
|
|
||||||
object UiUtil {
|
object UiUtil {
|
||||||
|
|
@ -862,14 +863,16 @@ object UiUtil {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.format_id.isBlank()) formatIdParent?.visibility = View.GONE
|
fun String?.doesntExist() : Boolean { return this.isNullOrBlank() || this == "None"}
|
||||||
|
|
||||||
|
if (format.format_id.doesntExist()) formatIdParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
formatIdParent?.findViewById<TextView>(R.id.format_id_value)?.text = format.format_id
|
formatIdParent?.findViewById<TextView>(R.id.format_id_value)?.text = format.format_id
|
||||||
formatIdParent?.setOnClickListener(clicker)
|
formatIdParent?.setOnClickListener(clicker)
|
||||||
formatIdParent?.setOnLongClickListener(longClicker)
|
formatIdParent?.setOnLongClickListener(longClicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.url.isNullOrBlank()) formatURLParent?.visibility = View.GONE
|
if (format.url.doesntExist()) formatURLParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
formatURLParent?.findViewById<TextView>(R.id.format_url_value)?.text = format.url
|
formatURLParent?.findViewById<TextView>(R.id.format_url_value)?.text = format.url
|
||||||
formatURLParent?.setOnClickListener(clicker)
|
formatURLParent?.setOnClickListener(clicker)
|
||||||
|
|
@ -877,7 +880,7 @@ object UiUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (format.container.isBlank()) containerParent?.visibility = View.GONE
|
if (format.container.doesntExist()) containerParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
containerParent?.findViewById<TextView>(R.id.container_value)?.text = format.container
|
containerParent?.findViewById<TextView>(R.id.container_value)?.text = format.container
|
||||||
containerParent?.setOnClickListener(clicker)
|
containerParent?.setOnClickListener(clicker)
|
||||||
|
|
@ -893,7 +896,7 @@ object UiUtil {
|
||||||
format.acodec.uppercase()
|
format.acodec.uppercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codecField.isBlank()) codecParent?.visibility = View.GONE
|
if (codecField.doesntExist()) codecParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
codecParent?.findViewById<TextView>(R.id.codec_value)?.text = codecField
|
codecParent?.findViewById<TextView>(R.id.codec_value)?.text = codecField
|
||||||
codecParent?.setOnClickListener(clicker)
|
codecParent?.setOnClickListener(clicker)
|
||||||
|
|
@ -907,28 +910,28 @@ object UiUtil {
|
||||||
filesizeParent?.setOnLongClickListener(longClicker)
|
filesizeParent?.setOnLongClickListener(longClicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.format_note.isBlank()) formatnoteParent?.visibility = View.GONE
|
if (format.format_note.doesntExist()) formatnoteParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
formatnoteParent?.findViewById<TextView>(R.id.format_note_value)?.text = format.format_note
|
formatnoteParent?.findViewById<TextView>(R.id.format_note_value)?.text = format.format_note
|
||||||
formatnoteParent?.setOnClickListener(clicker)
|
formatnoteParent?.setOnClickListener(clicker)
|
||||||
formatnoteParent?.setOnLongClickListener(longClicker)
|
formatnoteParent?.setOnLongClickListener(longClicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.fps.isNullOrBlank() || format.fps == "0") fpsParent?.visibility = View.GONE
|
if (format.fps.doesntExist() || format.fps == "0") fpsParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
fpsParent?.findViewById<TextView>(R.id.fps_value)?.text = format.fps
|
fpsParent?.findViewById<TextView>(R.id.fps_value)?.text = format.fps
|
||||||
fpsParent?.setOnClickListener(clicker)
|
fpsParent?.setOnClickListener(clicker)
|
||||||
fpsParent?.setOnLongClickListener(longClicker)
|
fpsParent?.setOnLongClickListener(longClicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.asr.isNullOrBlank()) asrParent?.visibility = View.GONE
|
if (format.asr.doesntExist()) asrParent?.visibility = View.GONE
|
||||||
else {
|
else {
|
||||||
asrParent?.findViewById<TextView>(R.id.asr_value)?.text = format.asr
|
asrParent?.findViewById<TextView>(R.id.asr_value)?.text = format.asr
|
||||||
asrParent?.setOnClickListener(clicker)
|
asrParent?.setOnClickListener(clicker)
|
||||||
asrParent?.setOnLongClickListener(longClicker)
|
asrParent?.setOnLongClickListener(longClicker)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format.tbr.isNullOrBlank()) bitrateParent?.visibility = View.GONE
|
if (format.tbr.doesntExist()) bitrateParent?.visibility = View.GONE
|
||||||
else{
|
else{
|
||||||
bitrateParent?.findViewById<TextView>(R.id.bitrate_value)?.text = format.tbr
|
bitrateParent?.findViewById<TextView>(R.id.bitrate_value)?.text = format.tbr
|
||||||
bitrateParent?.setOnClickListener(clicker)
|
bitrateParent?.setOnClickListener(clicker)
|
||||||
|
|
@ -990,7 +993,21 @@ object UiUtil {
|
||||||
val chips = mutableListOf<Chip>()
|
val chips = mutableListOf<Chip>()
|
||||||
context.getStringArray(R.array.subtitle_langs).forEachIndexed { index, s ->
|
context.getStringArray(R.array.subtitle_langs).forEachIndexed { index, s ->
|
||||||
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, chipGroup, false) as Chip
|
val tmp = context.layoutInflater.inflate(R.layout.filter_chip, chipGroup, false) as Chip
|
||||||
tmp.text = Locale(s).displayLanguage
|
s.split("-", ".*").run {
|
||||||
|
if (s.endsWith(".*")) {
|
||||||
|
val name = "${Locale(this[0]).displayName} (${context.getString(R.string.all)})"
|
||||||
|
tmp.text = name
|
||||||
|
}else{
|
||||||
|
if (this.size == 1) {
|
||||||
|
Locale(this[0])
|
||||||
|
} else {
|
||||||
|
Locale(this[0], this[1])
|
||||||
|
}.apply {
|
||||||
|
tmp.text = this.displayName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tmp.tag = s
|
tmp.tag = s
|
||||||
tmp.id = index
|
tmp.id = index
|
||||||
|
|
||||||
|
|
@ -1564,24 +1581,20 @@ object UiUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun handleNoResults(context: Activity, message: String, continueAnyway: Boolean = false, continued: () -> Unit, closed: () -> Unit) {
|
||||||
fun handleResultResponse(context: Activity, it: ResultViewModel.ResultsUiState, closed: () -> Unit){
|
|
||||||
val title = context.getString(it.errorMessage!!.first)
|
|
||||||
val message = it.errorMessage!!.second
|
|
||||||
|
|
||||||
val errDialog = MaterialAlertDialogBuilder(context)
|
val errDialog = MaterialAlertDialogBuilder(context)
|
||||||
.setTitle(title)
|
.setTitle(R.string.no_results)
|
||||||
.setMessage(message)
|
.setMessage(message)
|
||||||
|
|
||||||
for (a in it.actions!!){
|
errDialog.setPositiveButton(R.string.copy_log) { d:DialogInterface?, _:Int ->
|
||||||
when(a.second){
|
val clipboard: ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
ResultViewModel.ResultAction.COPY_LOG -> {
|
clipboard.setText(message)
|
||||||
errDialog.setPositiveButton(a.first) { d:DialogInterface?, _:Int ->
|
d?.dismiss()
|
||||||
val clipboard: ClipboardManager = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
}
|
||||||
clipboard.setText(message)
|
|
||||||
d?.dismiss()
|
if (continueAnyway) {
|
||||||
}
|
errDialog.setNeutralButton(R.string.continue_anyway) {d: DialogInterface?, _:Int ->
|
||||||
}
|
continued()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
package com.deniscerri.ytdl.work
|
package com.deniscerri.ytdl.work
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.content.res.Resources
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.util.DisplayMetrics
|
import android.util.DisplayMetrics
|
||||||
|
|
@ -20,6 +23,7 @@ import androidx.work.await
|
||||||
import androidx.work.workDataOf
|
import androidx.work.workDataOf
|
||||||
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
import com.afollestad.materialdialogs.utils.MDUtil.getStringArray
|
||||||
import com.deniscerri.ytdl.App
|
import com.deniscerri.ytdl.App
|
||||||
|
import com.deniscerri.ytdl.MainActivity
|
||||||
import com.deniscerri.ytdl.R
|
import com.deniscerri.ytdl.R
|
||||||
import com.deniscerri.ytdl.database.DBManager
|
import com.deniscerri.ytdl.database.DBManager
|
||||||
import com.deniscerri.ytdl.database.models.HistoryItem
|
import com.deniscerri.ytdl.database.models.HistoryItem
|
||||||
|
|
@ -73,15 +77,28 @@ class DownloadWorker(
|
||||||
//val createResultItem = inputData.getBoolean("createResultItem", true)
|
//val createResultItem = inputData.getBoolean("createResultItem", true)
|
||||||
|
|
||||||
val confTmp = Configuration(context.resources.configuration)
|
val confTmp = Configuration(context.resources.configuration)
|
||||||
val currLang = sharedPreferences.getString("app_language", "")!!.ifEmpty { Locale.getDefault().language }.split("-")
|
val locale = if (Build.VERSION.SDK_INT < 33) {
|
||||||
confTmp.setLocale(if (currLang.size == 1) Locale(currLang[0]) else Locale(currLang[0], currLang[1]))
|
sharedPreferences.getString("app_language", "")!!.ifEmpty { Locale.getDefault().language }
|
||||||
|
}else{
|
||||||
|
Locale.getDefault().language
|
||||||
|
}.run {
|
||||||
|
split("-")
|
||||||
|
}.run {
|
||||||
|
if (this.size == 1) Locale(this[0]) else Locale(this[0], this[1])
|
||||||
|
}
|
||||||
|
confTmp.setLocale(locale)
|
||||||
val metrics = DisplayMetrics()
|
val metrics = DisplayMetrics()
|
||||||
val resources = Resources(context.assets, metrics, confTmp)
|
val resources = Resources(context.assets, metrics, confTmp)
|
||||||
|
|
||||||
val pendingIntent = NavDeepLinkBuilder(context)
|
val openQueueIntent = Intent(context, MainActivity::class.java)
|
||||||
.setGraph(R.navigation.nav_graph)
|
openQueueIntent.setAction(Intent.ACTION_VIEW)
|
||||||
.setDestination(R.id.downloadQueueMainFragment)
|
openQueueIntent.putExtra("destination", "Queue")
|
||||||
.createPendingIntent()
|
val openDownloadQueue = PendingIntent.getActivity(
|
||||||
|
context,
|
||||||
|
1000000000,
|
||||||
|
openQueueIntent,
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
)
|
||||||
|
|
||||||
val workNotif = notificationUtil.createDefaultWorkerNotification()
|
val workNotif = notificationUtil.createDefaultWorkerNotification()
|
||||||
val foregroundInfo = ForegroundInfo(1000000000, workNotif)
|
val foregroundInfo = ForegroundInfo(1000000000, workNotif)
|
||||||
|
|
@ -112,7 +129,7 @@ class DownloadWorker(
|
||||||
val eligibleDownloads = items.take(if (concurrentDownloads < 0) 0 else concurrentDownloads).filter { it.id !in running }
|
val eligibleDownloads = items.take(if (concurrentDownloads < 0) 0 else concurrentDownloads).filter { it.id !in running }
|
||||||
|
|
||||||
eligibleDownloads.forEach{downloadItem ->
|
eligibleDownloads.forEach{downloadItem ->
|
||||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, downloadItem.title.ifEmpty { downloadItem.url }, downloadItem.id.toInt())
|
val notification = notificationUtil.createDownloadServiceNotification(openDownloadQueue, downloadItem.title.ifEmpty { downloadItem.url })
|
||||||
notificationUtil.notify(downloadItem.id.toInt(), notification)
|
notificationUtil.notify(downloadItem.id.toInt(), notification)
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
|
@ -189,7 +206,7 @@ class DownloadWorker(
|
||||||
}
|
}
|
||||||
//val wasQuickDownloaded = resultDao.getCountInt() == 0
|
//val wasQuickDownloaded = resultDao.getCountInt() == 0
|
||||||
runBlocking {
|
runBlocking {
|
||||||
var finalPaths : MutableList<String>?
|
var finalPaths = mutableListOf<String>()
|
||||||
|
|
||||||
if (noCache){
|
if (noCache){
|
||||||
eventBus.post(WorkerProgress(100, "Scanning Files", downloadItem.id))
|
eventBus.post(WorkerProgress(100, "Scanning Files", downloadItem.id))
|
||||||
|
|
@ -212,9 +229,6 @@ class DownloadWorker(
|
||||||
finalPaths.sortBy { File(it).lastModified() }
|
finalPaths.sortBy { File(it).lastModified() }
|
||||||
finalPaths = finalPaths.distinct().toMutableList()
|
finalPaths = finalPaths.distinct().toMutableList()
|
||||||
FileUtil.scanMedia(finalPaths, context)
|
FileUtil.scanMedia(finalPaths, context)
|
||||||
if (finalPaths.isEmpty()){
|
|
||||||
finalPaths = mutableListOf(context.getString(R.string.unfound_file))
|
|
||||||
}
|
|
||||||
}else{
|
}else{
|
||||||
//move file from internal to set download directory
|
//move file from internal to set download directory
|
||||||
eventBus.post(WorkerProgress(100, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
eventBus.post(WorkerProgress(100, "Moving file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
||||||
|
|
@ -227,11 +241,8 @@ class DownloadWorker(
|
||||||
|
|
||||||
if (finalPaths.isNotEmpty()){
|
if (finalPaths.isNotEmpty()){
|
||||||
eventBus.post(WorkerProgress(100, "Moved file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
eventBus.post(WorkerProgress(100, "Moved file to ${FileUtil.formatPath(downloadLocation)}", downloadItem.id))
|
||||||
}else{
|
|
||||||
finalPaths = mutableListOf(context.getString(R.string.unfound_file))
|
|
||||||
}
|
}
|
||||||
}catch (e: Exception){
|
}catch (e: Exception){
|
||||||
finalPaths = mutableListOf(context.getString(R.string.unfound_file))
|
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show()
|
||||||
|
|
@ -246,51 +257,52 @@ class DownloadWorker(
|
||||||
add("description")
|
add("description")
|
||||||
add("txt")
|
add("txt")
|
||||||
}
|
}
|
||||||
finalPaths = finalPaths?.filter { path -> !nonMediaExtensions.any { path.endsWith(it) } }?.toMutableList()
|
finalPaths = finalPaths.filter { path -> !nonMediaExtensions.any { path.endsWith(it) } }.toMutableList()
|
||||||
|
if (finalPaths.isEmpty()){
|
||||||
|
finalPaths = mutableListOf(context.getString(R.string.unfound_file))
|
||||||
|
}
|
||||||
FileUtil.deleteConfigFiles(request)
|
FileUtil.deleteConfigFiles(request)
|
||||||
|
|
||||||
//put download in history
|
//put download in history
|
||||||
if (!downloadItem.incognito) {
|
if (!downloadItem.incognito) {
|
||||||
if (request.hasOption("--download-archive") && finalPaths == listOf(context.getString(R.string.unfound_file))) {
|
if (request.hasOption("--download-archive") && finalPaths.isEmpty()) {
|
||||||
handler.postDelayed({
|
handler.postDelayed({
|
||||||
Toast.makeText(context, resources.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
Toast.makeText(context, resources.getString(R.string.download_already_exists), Toast.LENGTH_LONG).show()
|
||||||
}, 100)
|
}, 100)
|
||||||
}else{
|
}else{
|
||||||
val unixTime = System.currentTimeMillis() / 1000
|
val unixTime = System.currentTimeMillis() / 1000
|
||||||
finalPaths?.apply {
|
finalPaths.first().apply {
|
||||||
this.first().apply {
|
val file = File(this)
|
||||||
val file = File(this)
|
var duration = downloadItem.duration
|
||||||
var duration = downloadItem.duration
|
val d = file.getMediaDuration(context)
|
||||||
val d = file.getMediaDuration(context)
|
if (d > 0) duration = d.toStringDuration(Locale.US)
|
||||||
if (d > 0) duration = d.toStringDuration(Locale.US)
|
|
||||||
|
|
||||||
downloadItem.format.filesize = file.length()
|
downloadItem.format.filesize = file.length()
|
||||||
downloadItem.format.container = file.extension
|
downloadItem.format.container = file.extension
|
||||||
downloadItem.duration = duration
|
downloadItem.duration = duration
|
||||||
}
|
|
||||||
|
|
||||||
val historyItem = HistoryItem(0,
|
|
||||||
downloadItem.url,
|
|
||||||
downloadItem.title,
|
|
||||||
downloadItem.author,
|
|
||||||
downloadItem.duration,
|
|
||||||
downloadItem.thumb,
|
|
||||||
downloadItem.type,
|
|
||||||
unixTime,
|
|
||||||
this,
|
|
||||||
downloadItem.website,
|
|
||||||
downloadItem.format,
|
|
||||||
downloadItem.id,
|
|
||||||
commandString)
|
|
||||||
historyDao.insert(historyItem)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val historyItem = HistoryItem(0,
|
||||||
|
downloadItem.url,
|
||||||
|
downloadItem.title,
|
||||||
|
downloadItem.author,
|
||||||
|
downloadItem.duration,
|
||||||
|
downloadItem.thumb,
|
||||||
|
downloadItem.type,
|
||||||
|
unixTime,
|
||||||
|
finalPaths,
|
||||||
|
downloadItem.website,
|
||||||
|
downloadItem.format,
|
||||||
|
downloadItem.id,
|
||||||
|
commandString)
|
||||||
|
historyDao.insert(historyItem)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationUtil.cancelDownloadNotification(downloadItem.id.toInt())
|
notificationUtil.cancelDownloadNotification(downloadItem.id.toInt())
|
||||||
notificationUtil.createDownloadFinished(
|
notificationUtil.createDownloadFinished(
|
||||||
downloadItem.id, downloadItem.title, downloadItem.type, if (finalPaths?.first().equals(context.getString(R.string.unfound_file))) null else finalPaths, resources
|
downloadItem.id, downloadItem.title, downloadItem.type, if (finalPaths.first().equals(context.getString(R.string.unfound_file))) null else finalPaths, resources
|
||||||
)
|
)
|
||||||
|
|
||||||
// if (wasQuickDownloaded && createResultItem){
|
// if (wasQuickDownloaded && createResultItem){
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ class TerminalDownloadWorker(
|
||||||
|
|
||||||
val intent = Intent(context, TerminalActivity::class.java)
|
val intent = Intent(context, TerminalActivity::class.java)
|
||||||
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, command.take(65), itemId)
|
val notification = notificationUtil.createDownloadServiceNotification(pendingIntent, command.take(65))
|
||||||
val foregroundInfo = ForegroundInfo(itemId, notification)
|
val foregroundInfo = ForegroundInfo(itemId, notification)
|
||||||
setForegroundAsync(foregroundInfo)
|
setForegroundAsync(foregroundInfo)
|
||||||
|
|
||||||
|
|
|
||||||
5
app/src/main/res/drawable/baseline_album_24.xml
Normal file
5
app/src/main/res/drawable/baseline_album_24.xml
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?android:colorAccent" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||||
|
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5 -2.01,4.5 -4.5,4.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z"/>
|
||||||
|
|
||||||
|
</vector>
|
||||||
|
|
@ -8,5 +8,5 @@
|
||||||
android:bottom="1dp"
|
android:bottom="1dp"
|
||||||
android:top="1dp" />
|
android:top="1dp" />
|
||||||
|
|
||||||
<corners android:radius="3dp" />
|
<corners android:radius="5dp" />
|
||||||
</shape>
|
</shape>
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:paddingVertical="10dp"
|
android:paddingVertical="10dp"
|
||||||
android:layout_height="80dp">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/downloads_image_view"
|
android:id="@+id/downloads_image_view"
|
||||||
|
|
@ -49,13 +49,12 @@
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
app:layout_constraintEnd_toStartOf="@+id/download_item_data"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar" />
|
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar2" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:id="@+id/download_item_data"
|
android:id="@+id/download_item_data"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/options"
|
app:layout_constraintEnd_toStartOf="@+id/options"
|
||||||
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
|
app:layout_constraintStart_toEndOf="@+id/downloads_image_view"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
|
@ -66,7 +65,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="1"
|
||||||
android:paddingHorizontal="5dp"
|
android:paddingHorizontal="5dp"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
|
|
@ -76,11 +75,11 @@
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<HorizontalScrollView
|
<HorizontalScrollView
|
||||||
|
android:id="@+id/horizontalScrollView"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="bottom"
|
android:gravity="bottom"
|
||||||
android:scrollbars="none"
|
android:scrollbars="none"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="0.0"
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
|
@ -90,27 +89,30 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/download_type"
|
android:id="@+id/download_type"
|
||||||
|
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="5dp"
|
android:layout_marginHorizontal="5dp"
|
||||||
android:background="@drawable/rounded_corner"
|
android:background="@drawable/rounded_corner"
|
||||||
android:backgroundTint="?attr/colorPrimaryContainer"
|
android:backgroundTint="?attr/colorSecondary"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
|
android:ellipsize="end"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:maxLength="17"
|
||||||
|
android:minWidth="30dp"
|
||||||
android:paddingHorizontal="5dp"
|
android:paddingHorizontal="5dp"
|
||||||
android:textColor="@color/white"
|
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
app:drawableStartCompat="@drawable/ic_music_formatcard"
|
app:drawableStartCompat="@drawable/ic_music_formatcard"
|
||||||
app:drawableTint="@color/white"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_bias="0.0" />
|
app:layout_constraintVertical_bias="0.0" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/file_size"
|
android:id="@+id/file_size"
|
||||||
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
|
||||||
|
|
@ -123,7 +125,6 @@
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="30dp"
|
android:minWidth="30dp"
|
||||||
android:paddingHorizontal="5dp"
|
android:paddingHorizontal="5dp"
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
@ -142,10 +143,8 @@
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:maxLength="17"
|
android:maxLength="17"
|
||||||
android:maxLines="1"
|
|
||||||
android:minWidth="30dp"
|
android:minWidth="30dp"
|
||||||
android:paddingHorizontal="5dp"
|
android:paddingHorizontal="5dp"
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
@ -161,10 +160,11 @@
|
||||||
android:background="@drawable/rounded_corner"
|
android:background="@drawable/rounded_corner"
|
||||||
android:backgroundTint="?attr/colorSecondary"
|
android:backgroundTint="?attr/colorSecondary"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
|
android:ellipsize="end"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
|
android:maxLength="17"
|
||||||
android:minWidth="30dp"
|
android:minWidth="30dp"
|
||||||
android:paddingHorizontal="5dp"
|
android:paddingHorizontal="5dp"
|
||||||
android:textSize="12sp"
|
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
|
@ -172,12 +172,24 @@
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</HorizontalScrollView>
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/output"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:layout_margin="5dp"
|
||||||
|
android:textSize="13sp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/horizontalScrollView" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@
|
||||||
app:layout_constraintHorizontal_weight="0.3"
|
app:layout_constraintHorizontal_weight="0.3"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar" />
|
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar2" />
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/incognitoLabel"
|
android:id="@+id/incognitoLabel"
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,6 @@
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:cornerRadius="10dp"
|
app:cornerRadius="10dp"
|
||||||
app:drawableStartCompat="@drawable/ic_music_formatcard"
|
app:drawableStartCompat="@drawable/ic_music_formatcard"
|
||||||
app:drawableTint="@color/white"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
@ -173,6 +172,7 @@
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/format_id"
|
android:id="@+id/format_id"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
android:minWidth="70dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_alignParentTop="true"
|
android:layout_alignParentTop="true"
|
||||||
android:layout_alignParentEnd="true"
|
android:layout_alignParentEnd="true"
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,33 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
tools:context="com.deniscerri.ytdl.ui.more.terminal.TerminalActivity">
|
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/appbarlayout"
|
||||||
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:liftOnScroll="false"
|
|
||||||
android:background="@android:color/transparent"
|
android:background="@android:color/transparent"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:liftOnScroll="false">
|
||||||
|
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/title"
|
android:id="@+id/title"
|
||||||
android:elevation="0dp"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
app:navigationIcon="@drawable/ic_back"
|
android:layout_height="match_parent"
|
||||||
|
android:elevation="0dp"
|
||||||
app:navigationContentDescription="@string/back"
|
app:navigationContentDescription="@string/back"
|
||||||
android:layout_height="match_parent"/>
|
app:navigationIcon="@drawable/ic_back" />
|
||||||
|
|
||||||
<com.google.android.material.slider.Slider
|
<com.google.android.material.slider.Slider
|
||||||
android:visibility="gone"
|
|
||||||
android:id="@+id/textsize_seekbar"
|
android:id="@+id/textsize_seekbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
||||||
|
|
@ -34,34 +36,45 @@
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
android:id="@+id/frameLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/coordinatorLayout3"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/appbarlayout">
|
||||||
|
|
||||||
<me.zhanghai.android.fastscroll.FastScrollScrollView
|
<me.zhanghai.android.fastscroll.FastScrollScrollView
|
||||||
android:id="@+id/content_scrollview"
|
android:id="@+id/content_scrollview"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false">
|
||||||
>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="150dp"
|
|
||||||
android:focusableInTouchMode="true"
|
android:focusableInTouchMode="true"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
<HorizontalScrollView
|
||||||
android:id="@+id/content"
|
|
||||||
android:padding="10dp"
|
|
||||||
android:fontFamily="monospace"
|
|
||||||
android:textSize="15sp"
|
|
||||||
android:gravity="bottom"
|
|
||||||
android:scrollbars="none"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:textIsSelectable="true"
|
android:id="@+id/horizontalscroll_output"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/content"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="monospace"
|
||||||
|
android:gravity="bottom"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:textIsSelectable="true"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
</HorizontalScrollView>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
@ -69,27 +82,41 @@
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<include layout="@layout/no_results"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||||
android:visibility="gone" />
|
android:id="@+id/coordinatorLayout3"
|
||||||
|
android:layout_width="0dp"
|
||||||
<com.google.android.material.bottomappbar.BottomAppBar
|
|
||||||
android:id="@+id/bottomAppBar"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="bottom"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
style="@style/Widget.Material3.BottomAppBar"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:menu="@menu/log_detail_menu"
|
app:layout_constraintStart_toStartOf="parent">
|
||||||
/>
|
|
||||||
|
|
||||||
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
<com.google.android.material.bottomappbar.BottomAppBar
|
||||||
android:id="@+id/copy_log"
|
android:id="@+id/bottomAppBar"
|
||||||
android:layout_width="wrap_content"
|
style="@style/Widget.Material3.BottomAppBar"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:contentDescription="@string/copy_log"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/copy_log"
|
android:layout_gravity="bottom"
|
||||||
app:layout_anchor="@id/bottomAppBar"
|
app:layout_constraintBottom_toBottomOf="@+id/frameLayout"
|
||||||
app:icon="@drawable/ic_copy"/>
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:menu="@menu/log_detail_menu" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
|
android:id="@+id/copy_log"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/copy_log"
|
||||||
|
android:text="@string/copy_log"
|
||||||
|
app:icon="@drawable/ic_copy"
|
||||||
|
app:layout_anchor="@id/bottomAppBar" />
|
||||||
|
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
<include
|
||||||
|
layout="@layout/no_results"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/appbarlayout"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/coordinatorLayout3"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/frameLayout" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
@ -67,7 +67,7 @@
|
||||||
app:layout_constraintHorizontal_weight="0.3"
|
app:layout_constraintHorizontal_weight="0.3"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar" />
|
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar2" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|
|
||||||
|
|
@ -101,9 +101,12 @@
|
||||||
android:id="@+id/download_music"
|
android:id="@+id/download_music"
|
||||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
|
app:elevation="0dp"
|
||||||
|
android:elevation="0dp"
|
||||||
|
app:borderWidth="0dp"
|
||||||
android:contentDescription="@string/audio"
|
android:contentDescription="@string/audio"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
android:layout_marginHorizontal="10dp"
|
android:layout_marginHorizontal="5dp"
|
||||||
app:icon="@drawable/ic_music"
|
app:icon="@drawable/ic_music"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
app:layout_constraintEnd_toStartOf="@+id/download_video"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
@ -113,8 +116,9 @@
|
||||||
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
style="@style/Widget.Material3.ExtendedFloatingActionButton.Icon.Secondary"
|
||||||
android:layout_width="55dp"
|
android:layout_width="55dp"
|
||||||
android:layout_height="55dp"
|
android:layout_height="55dp"
|
||||||
|
app:elevation="0dp"
|
||||||
android:contentDescription="@string/video"
|
android:contentDescription="@string/video"
|
||||||
android:layout_marginHorizontal="10dp"
|
android:layout_marginHorizontal="5dp"
|
||||||
app:icon="@drawable/ic_video"
|
app:icon="@drawable/ic_video"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
|
||||||
|
|
@ -3,19 +3,19 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
tools:context=".MainActivity" >
|
tools:context=".MainActivity" >
|
||||||
|
|
||||||
<group>
|
<!-- <group>-->
|
||||||
<item
|
<!-- <item-->
|
||||||
android:id="@+id/pause"
|
<!-- android:id="@+id/pause"-->
|
||||||
android:title="@string/pause"
|
<!-- android:title="@string/pause"-->
|
||||||
android:icon="@drawable/exomedia_ic_pause_white"
|
<!-- android:icon="@drawable/exomedia_ic_pause_white"-->
|
||||||
app:showAsAction="ifRoom" />
|
<!-- app:showAsAction="ifRoom" />-->
|
||||||
|
|
||||||
<item
|
<!-- <item-->
|
||||||
android:id="@+id/resume"
|
<!-- android:id="@+id/resume"-->
|
||||||
android:title="@string/resume"
|
<!-- android:title="@string/resume"-->
|
||||||
android:icon="@drawable/exomedia_ic_play_arrow_white"
|
<!-- android:icon="@drawable/exomedia_ic_play_arrow_white"-->
|
||||||
app:showAsAction="ifRoom" />
|
<!-- app:showAsAction="ifRoom" />-->
|
||||||
</group>
|
<!-- </group>-->
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/cancel"
|
android:id="@+id/cancel"
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@
|
||||||
<item
|
<item
|
||||||
android:id="@+id/scroll_down"
|
android:id="@+id/scroll_down"
|
||||||
android:title="@string/scroll_down"
|
android:title="@string/scroll_down"
|
||||||
android:visible="false"
|
|
||||||
android:icon="@drawable/ic_down"
|
android:icon="@drawable/ic_down"
|
||||||
app:showAsAction="always" />
|
app:showAsAction="always" />
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1029,13 +1029,16 @@
|
||||||
<item>en-IN</item>,
|
<item>en-IN</item>,
|
||||||
<item>en-GB</item>,
|
<item>en-GB</item>,
|
||||||
<item>en</item>,
|
<item>en</item>,
|
||||||
|
<item>en.*</item>,
|
||||||
<item>es</item>,
|
<item>es</item>,
|
||||||
<item>es-419</item>,
|
<item>es-419</item>,
|
||||||
<item>es-US</item>,
|
<item>es-US</item>,
|
||||||
|
<item>es.*</item>,
|
||||||
<item>eu</item>,
|
<item>eu</item>,
|
||||||
<item>fil</item>,
|
<item>fil</item>,
|
||||||
<item>fr</item>,
|
<item>fr</item>,
|
||||||
<item>fr-CA</item>,
|
<item>fr-CA</item>,
|
||||||
|
<item>fr.*</item>,
|
||||||
<item>gl</item>,
|
<item>gl</item>,
|
||||||
<item>hr</item>,
|
<item>hr</item>,
|
||||||
<item>zu</item>,
|
<item>zu</item>,
|
||||||
|
|
@ -1051,6 +1054,7 @@
|
||||||
<item>pl</item>,
|
<item>pl</item>,
|
||||||
<item>pt-PT</item>,
|
<item>pt-PT</item>,
|
||||||
<item>pt</item>,
|
<item>pt</item>,
|
||||||
|
<item>pt.*</item>,
|
||||||
<item>ro</item>,
|
<item>ro</item>,
|
||||||
<item>sq</item>,
|
<item>sq</item>,
|
||||||
<item>sk</item>,
|
<item>sk</item>,
|
||||||
|
|
@ -1097,6 +1101,7 @@
|
||||||
<item>zh-CN</item>,
|
<item>zh-CN</item>,
|
||||||
<item>zh-TW</item>,
|
<item>zh-TW</item>,
|
||||||
<item>zh-HK</item>,
|
<item>zh-HK</item>,
|
||||||
|
<item>zh.*</item>,
|
||||||
<item>ja</item>,
|
<item>ja</item>,
|
||||||
<item>ko</item>
|
<item>ko</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
|
||||||
|
|
@ -418,4 +418,7 @@
|
||||||
<string name="weekly">Weekly</string>
|
<string name="weekly">Weekly</string>
|
||||||
<string name="monthly">Monthly</string>
|
<string name="monthly">Monthly</string>
|
||||||
<string name="cleanup_leftover_downloads">Clean-up leftover downloads (cancelled, errored)</string>
|
<string name="cleanup_leftover_downloads">Clean-up leftover downloads (cancelled, errored)</string>
|
||||||
|
<string name="continue_anyway">Continue Anyway</string>
|
||||||
|
<string name="playlist_as_album">Use Playlist Name as Album Metadata</string>
|
||||||
|
<string name="playlist_as_album_summary">If Album Metadata is not present, use playlist name instead</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
@ -32,6 +32,11 @@
|
||||||
<item name="cornerSize">5dp</item>
|
<item name="cornerSize">5dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="ShapeAppearanceOverlay.Avatar2" parent="ShapeAppearance.MaterialComponents.SmallComponent">
|
||||||
|
<item name="cornerFamily">rounded</item>
|
||||||
|
<item name="cornerSize">7dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="ShapeAppearanceOverlay.Chip.Rounded" parent="ShapeAppearance.MaterialComponents.SmallComponent">
|
<style name="ShapeAppearanceOverlay.Chip.Rounded" parent="ShapeAppearance.MaterialComponents.SmallComponent">
|
||||||
<item name="cornerFamily">rounded</item>
|
<item name="cornerFamily">rounded</item>
|
||||||
<item name="cornerSizeTopLeft">12dp</item>
|
<item name="cornerSizeTopLeft">12dp</item>
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,14 @@
|
||||||
app:summary="@string/crop_thumb_summary"
|
app:summary="@string/crop_thumb_summary"
|
||||||
app:title="@string/crop_thumb" />
|
app:title="@string/crop_thumb" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
android:widgetLayout="@layout/preferece_material_switch"
|
||||||
|
app:defaultValue="true"
|
||||||
|
app:icon="@drawable/baseline_album_24"
|
||||||
|
app:key="playlist_as_album"
|
||||||
|
app:summary="@string/playlist_as_album_summary"
|
||||||
|
app:title="@string/playlist_as_album" />
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue