more features

This commit is contained in:
deniscerri 2024-11-23 19:40:08 +01:00
parent e1c99e2647
commit 0df5a9e194
No known key found for this signature in database
GPG key ID: 95C43D517D830350
13 changed files with 127 additions and 82 deletions

View file

@ -3,8 +3,9 @@ plugins {
id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1' id 'com.google.android.libraries.mapsplatform.secrets-gradle-plugin' version '2.0.1'
id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.android'
id 'com.google.devtools.ksp' id 'com.google.devtools.ksp'
id "org.jetbrains.kotlin.plugin.serialization" version "1.8.10" id "org.jetbrains.kotlin.plugin.serialization" version "2.0.21"
id "org.jetbrains.kotlin.plugin.parcelize" version "1.8.10" id "org.jetbrains.kotlin.plugin.parcelize" version "2.0.21"
id "org.jetbrains.kotlin.plugin.compose" version "2.0.21"
} }
def properties = new Properties() def properties = new Properties()
@ -101,6 +102,7 @@ android {
buildFeatures { buildFeatures {
viewBinding true viewBinding true
buildConfig true
compose true compose true
} }
@ -195,7 +197,7 @@ dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0' implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0'
implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4' implementation 'it.xabaras.android:recyclerview-swipedecorator:1.4'
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.6" implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.6"
implementation "com.github.Irineu333:Highlight-KT:1.0.4" implementation "com.neoutils.highlight:highlight-view:2.2.0"
// For media playback using ExoPlayer // For media playback using ExoPlayer
implementation("androidx.media3:media3-exoplayer:$media3_version") implementation("androidx.media3:media3-exoplayer:$media3_version")

View file

@ -228,6 +228,9 @@ interface DownloadDao {
@Query("UPDATE downloads set status=:status where id=:id") @Query("UPDATE downloads set status=:status where id=:id")
suspend fun setStatus(id: Long, status: String) suspend fun setStatus(id: Long, status: String)
@Query("UPDATE downloads set status=:status where id IN (:ids)")
suspend fun setStatusMultiple(ids: List<Long>, status: String)
@Update @Update
suspend fun updateWithoutUpsert(item: DownloadItem) suspend fun updateWithoutUpsert(item: DownloadItem)

View file

@ -123,6 +123,10 @@ class DownloadRepository(private val downloadDao: DownloadDao) {
downloadDao.setStatus(id, status.toString()) downloadDao.setStatus(id, status.toString())
} }
suspend fun setDownloadStatusMultiple(ids: List<Long>, status: Status) {
downloadDao.setStatusMultiple(ids, status.toString())
}
fun getItemByID(id: Long) : DownloadItem { fun getItemByID(id: Long) : DownloadItem {
return downloadDao.getDownloadById(id) return downloadDao.getDownloadById(id)
} }

View file

@ -1268,9 +1268,7 @@ class DownloadViewModel(private val application: Application) : AndroidViewModel
} }
delay(1000) delay(1000)
isPausingResuming = false isPausingResuming = false
activeDownloadsList.forEach { repository.setDownloadStatusMultiple(activeDownloadsList.map { it.id }, DownloadRepository.Status.Paused)
repository.setDownloadStatus(it.id, DownloadRepository.Status.Paused)
}
pausedAllDownloads.value = PausedAllDownloadsState.RESUME pausedAllDownloads.value = PausedAllDownloadsState.RESUME
} }

View file

@ -71,6 +71,10 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
text = finalText text = finalText
} }
card.findViewById<TextView>(R.id.dataFetchingExtraCommands).apply {
isVisible = item.useAsExtraCommandDataFetching
}
card.findViewById<TextView>(R.id.preferredTemplate).apply { card.findViewById<TextView>(R.id.preferredTemplate).apply {
val preferred = sharedPreferences.getString("preferred_command_template", "") val preferred = sharedPreferences.getString("preferred_command_template", "")
isVisible = preferred == item.content isVisible = preferred == item.content
@ -165,7 +169,8 @@ class TemplatesAdapter(onItemClickListener: OnItemClickListener, activity: Activ
oldItem.content == newItem.content && oldItem.content == newItem.content &&
oldItem.useAsExtraCommand == newItem.useAsExtraCommand && oldItem.useAsExtraCommand == newItem.useAsExtraCommand &&
oldItem.useAsExtraCommandAudio == newItem.useAsExtraCommandAudio && oldItem.useAsExtraCommandAudio == newItem.useAsExtraCommandAudio &&
oldItem.useAsExtraCommandVideo == newItem.useAsExtraCommandVideo oldItem.useAsExtraCommandVideo == newItem.useAsExtraCommandVideo &&
oldItem.useAsExtraCommandDataFetching == newItem.useAsExtraCommandDataFetching
} }
} }
} }

View file

@ -46,11 +46,12 @@ import com.deniscerri.ytdl.database.repository.ObserveSourcesRepository.EveryCat
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.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.gson.Gson import com.neoutils.highlight.core.Highlight
import com.google.gson.JsonArray import com.neoutils.highlight.core.scheme.TextColorScheme
import com.neo.highlight.core.Highlight import com.neoutils.highlight.core.util.Match
import com.neo.highlight.util.listener.HighlightTextWatcher import com.neoutils.highlight.core.util.UiColor
import com.neo.highlight.util.scheme.ColorScheme import com.neoutils.highlight.view.extension.toSpannedString
import com.neoutils.highlight.view.text.HighlightTextWatcher
import com.squareup.picasso.Picasso import com.squareup.picasso.Picasso
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
@ -72,28 +73,27 @@ object Extensions {
return (metrics.density * px).toInt() return (metrics.density * px).toInt()
} }
private var textHighLightSchemes = listOf( private var textHighlightSchemes = listOf(
ColorScheme(Pattern.compile("([\"'])(?:\\\\1|.)*?\\1"), Color.parseColor("#FC8500")), TextColorScheme(regex = "([\"'])(?:\\\\1|.)*?\\1".toRegex(), match = Match.fully(UiColor.Hex("#FC8500"))),
ColorScheme(Pattern.compile("yt-dlp"), Color.parseColor("#77eb09")), TextColorScheme(regex = "yt-dlp".toRegex(), match = Match.fully(UiColor.Hex("#77eb09"))),
ColorScheme(Pattern.compile("(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"), Color.parseColor("#b5942f")), TextColorScheme(regex = "(https?://(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?://(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})".toRegex(), match = Match.fully(UiColor.Hex("#b5942f"))),
ColorScheme(Pattern.compile("\\d+(\\.\\d)?%"), Color.parseColor("#43a564")) TextColorScheme(regex = "\\d+(\\.\\d)?%".toRegex(), match = Match.fully(UiColor.Hex("#43a564"))),
) )
fun View.enableTextHighlight(){ fun View.enableTextHighlight(){
if (this is EditText || this is TextView){ if (this is EditText || this is TextView){
//init syntax highlighter //init syntax highlighter
val highlight = Highlight() val highlight = Highlight(textHighlightSchemes)
val highlightWatcher = HighlightTextWatcher() val highlightWatcher = HighlightTextWatcher(highlight)
highlight.addScheme( if (this is EditText) {
*textHighLightSchemes.map { it }.toTypedArray() this.addTextChangedListener(highlightWatcher)
) this.setText(highlight.toSpannedString(this.text.toString()))
highlightWatcher.addScheme( }else if (this is TextView) {
*textHighLightSchemes.map { it }.toTypedArray() this.addTextChangedListener(highlightWatcher)
) this.text = highlight.toSpannedString(this.text.toString())
}
highlight.setSpan(this as TextView)
this.addTextChangedListener(highlightWatcher)
} }
} }

View file

@ -108,7 +108,7 @@ object FileUtil {
if (it.isDirectory && it.absolutePath == originDir.absolutePath) return@forEach if (it.isDirectory && it.absolutePath == originDir.absolutePath) return@forEach
var destFile: DocumentFile var destFile: DocumentFile
try { try {
if (it.name.matches("(^config.*.\\.txt\$)|(rList)|(.*.part-Frag.*)|(.*.live_chat)|(.*.ytdl)".toRegex())){ if (it.name.matches("(^config.*.\\.txt\$)|(rList)|(.*.part-Frag.*)|(.*.live_chat)|(.*.ytdl)|(.*.info.json)".toRegex())){
return@forEach return@forEach
} }

View file

@ -725,6 +725,18 @@ class YTDLPUtil(private val context: Context) {
request.addOption("--download-archive", FileUtil.getDownloadArchivePath(context)) request.addOption("--download-archive", FileUtil.getDownloadArchivePath(context))
} }
if (!sharedPreferences.getBoolean("disable_write_info_json", false)) {
val infoJsonFile = downDir.walkTopDown().firstOrNull { it.name == "${downloadItem.id}.info.json" }
//ignore info file if its older than 5 hours. puny measure to prevent expired formats in some cases
if (infoJsonFile == null || System.currentTimeMillis() - infoJsonFile.lastModified() > (1000 * 60 * 60 * 5)) {
request.addOption("--write-info-json")
request.addOption("--no-clean-info-json")
request.addOption("-o", "infojson:${downloadItem.id}")
}else {
request.addOption("--load-info-json", infoJsonFile.absolutePath)
}
}
val preferredAudioCodec = sharedPreferences.getString("audio_codec", "")!! val preferredAudioCodec = sharedPreferences.getString("audio_codec", "")!!
val aCodecPrefIndex = context.getStringArray(R.array.audio_codec_values).indexOf(preferredAudioCodec) val aCodecPrefIndex = context.getStringArray(R.array.audio_codec_values).indexOf(preferredAudioCodec)
val aCodecPref = runCatching { context.getStringArray(R.array.audio_codec_values_ytdlp)[aCodecPrefIndex] }.getOrElse { "" } val aCodecPref = runCatching { context.getStringArray(R.array.audio_codec_values_ytdlp)[aCodecPrefIndex] }.getOrElse { "" }

View file

@ -41,64 +41,75 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title" /> app:layout_constraintTop_toBottomOf="@+id/title" />
<HorizontalScrollView <com.google.android.material.chip.ChipGroup
android:layout_width="wrap_content"
android:scrollbars="none"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/content" app:layout_constraintTop_toBottomOf="@id/content"
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<LinearLayout <TextView
android:id="@+id/preferredTemplate"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary"
android:visibility="gone"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent"> android:layout_height="wrap_content"
android:background="@drawable/rounded_corner"
android:backgroundTint="?attr/colorPrimaryContainer"
android:clickable="false"
android:gravity="center"
android:minWidth="30dp"
android:paddingHorizontal="5dp"
android:textSize="12sp"
android:textStyle="bold"
app:cornerRadius="10dp"
android:text="@string/preferred_command_template"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<TextView <TextView
android:id="@+id/preferredTemplate" android:id="@+id/useInExtraCommands"
style="@style/Widget.Material3.FloatingActionButton.Large.Primary" style="@style/Widget.Material3.FloatingActionButton.Large.Secondary"
android:layout_width="wrap_content" android:visibility="gone"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_marginEnd="5dp" android:layout_height="wrap_content"
android:background="@drawable/rounded_corner" android:text="@string/extra_command"
android:backgroundTint="?attr/colorPrimaryContainer" android:background="@drawable/rounded_corner"
android:clickable="false" android:backgroundTint="?attr/colorSecondaryContainer"
android:gravity="center" android:clickable="false"
android:visibility="gone" android:gravity="center"
android:minWidth="30dp" android:minWidth="30dp"
android:paddingHorizontal="5dp" android:paddingHorizontal="5dp"
android:textSize="12sp" android:textSize="12sp"
android:textStyle="bold" android:textStyle="bold"
app:cornerRadius="10dp" app:cornerRadius="10dp"
android:text="@string/preferred_command_template" 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"/>
<TextView <TextView
android:id="@+id/useInExtraCommands" android:id="@+id/dataFetchingExtraCommands"
style="@style/Widget.Material3.FloatingActionButton.Large.Secondary" style="@style/Widget.Material3.FloatingActionButton.Large.Tertiary"
android:layout_width="wrap_content" android:visibility="gone"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:visibility="gone" android:layout_height="wrap_content"
android:layout_marginEnd="5dp" android:text="@string/data_fetching_extra_command"
android:text="@string/extra_command" android:background="@drawable/rounded_corner"
android:background="@drawable/rounded_corner" android:backgroundTint="?attr/colorTertiaryContainer"
android:backgroundTint="?attr/colorSecondaryContainer" android:clickable="false"
android:clickable="false" android:gravity="center"
android:gravity="center" android:minWidth="30dp"
android:minWidth="30dp" android:paddingHorizontal="5dp"
android:paddingHorizontal="5dp" android:textSize="12sp"
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" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout> </com.google.android.material.chip.ChipGroup>
</HorizontalScrollView>

View file

@ -437,4 +437,6 @@
<string name="data_fetching_extra_command">Data Fetching Extra Command</string> <string name="data_fetching_extra_command">Data Fetching Extra Command</string>
<string name="thumbnail">Thumbnail</string> <string name="thumbnail">Thumbnail</string>
<string name="data_fetching_extra_command_summary">Enable command templates to be used for data fetching as extra commands</string> <string name="data_fetching_extra_command_summary">Enable command templates to be used for data fetching as extra commands</string>
<string name="disable_write_info_json">Disable Write Info Json</string>
<string name="disable_write_info_json_summary">(Not Recommended) Every time you restart / resume the download, yt-dlp will re-download json data from the servers.</string>
</resources> </resources>

View file

@ -33,4 +33,12 @@
android:title="@string/data_fetching_extra_command" /> android:title="@string/data_fetching_extra_command" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory android:title="@string/downloading">
<SwitchPreferenceCompat
android:icon="@drawable/if_file_rename"
android:key="disable_write_info_json"
android:summary="@string/disable_write_info_json_summary"
android:title="@string/disable_write_info_json" />
</PreferenceCategory>
</PreferenceScreen> </PreferenceScreen>

View file

@ -41,11 +41,11 @@ buildscript {
plugins { plugins {
id 'com.android.application' version '8.5.2' apply false id 'com.android.application' version '8.5.2' apply false
id 'com.android.library' version '8.5.2' apply false id 'com.android.library' version '8.5.2' apply false
id 'org.jetbrains.kotlin.android' version '1.8.10' apply false id 'org.jetbrains.kotlin.android' version '2.0.21' apply false
id "org.jetbrains.kotlin.plugin.serialization" version "1.8.10" apply false id "org.jetbrains.kotlin.plugin.serialization" version "2.0.21" apply false
id "org.jetbrains.kotlin.plugin.parcelize" version "1.8.10" apply false id "org.jetbrains.kotlin.plugin.parcelize" version "2.0.21" apply false
id 'com.android.test' version '8.5.2' apply false id 'com.android.test' version '8.5.2' apply false
id 'com.google.devtools.ksp' version '1.8.10-1.0.9' apply false id 'com.google.devtools.ksp' version '2.0.21-1.0.28' apply false
} }
tasks.register('clean', Delete) { tasks.register('clean', Delete) {

View file

@ -11,9 +11,9 @@
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Sun Oct 08 20:53:48 CEST 2023 #Sun Oct 08 20:53:48 CEST 2023
android.defaults.buildfeatures.buildconfig=true
android.enableJetifier=true android.enableJetifier=true
android.nonFinalResIds=false android.nonFinalResIds=false
android.nonTransitiveRClass=false android.nonTransitiveRClass=false
android.suppressUnsupportedCompileSdk=35
android.useAndroidX=true android.useAndroidX=true
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1024M" -Dfile.encoding\=UTF-8 org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1024M" -Dfile.encoding\=UTF-8