This commit is contained in:
deniscerri 2023-05-01 12:51:22 +02:00
parent 6a2e827d77
commit 888dabc352
No known key found for this signature in database
GPG key ID: 95C43D517D830350
22 changed files with 115 additions and 76 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" /> <component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="jbr-17" project-jdk-type="JavaSDK" /> <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="corretto-17" project-jdk-type="JavaSDK" />
</project> </project>

View file

@ -97,12 +97,12 @@ android {
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_11 sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_11 targetCompatibility JavaVersion.VERSION_17
} }
kotlinOptions { kotlinOptions {
jvmTarget = '11' jvmTarget = '17'
} }
splits { splits {

View file

@ -61,4 +61,8 @@
public <init>(android.content.Context,androidx.work.WorkerParameters); public <init>(android.content.Context,androidx.work.WorkerParameters);
} }
-dontobfuscate -dontobfuscate
-dontwarn com.google.android.exoplayer2.**
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken

View file

@ -12,6 +12,9 @@ interface ResultDao {
@Query("SELECT COUNT(id) FROM results") @Query("SELECT COUNT(id) FROM results")
fun getCount() : LiveData<Int> fun getCount() : LiveData<Int>
@Query("SELECT COUNT(id) FROM results")
fun getCountInt() :Int
@Query("SELECT * FROM results LIMIT 1") @Query("SELECT * FROM results LIMIT 1")
fun getFirstResult() : ResultItem fun getFirstResult() : ResultItem

View file

@ -33,7 +33,7 @@ import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
import com.google.android.exoplayer2.source.MediaSource import com.google.android.exoplayer2.source.MediaSource
import com.google.android.exoplayer2.source.MergingMediaSource import com.google.android.exoplayer2.source.MergingMediaSource
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
import com.google.android.exoplayer2.ui.PlayerView import com.google.android.exoplayer2.ui.StyledPlayerView
import com.google.android.exoplayer2.util.MimeTypes import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.bottomsheet.BottomSheetDialogFragment
@ -96,7 +96,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
} }
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi", "SetTextI18n")
override fun setupDialog(dialog: Dialog, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style) super.setupDialog(dialog, style)
val view = LayoutInflater.from(context).inflate(R.layout.cut_video_sheet, null) val view = LayoutInflater.from(context).inflate(R.layout.cut_video_sheet, null)
@ -106,14 +106,14 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels / 2 behavior.peekHeight = displayMetrics.heightPixels
} }
val renderersFactory = DefaultRenderersFactory(requireContext().applicationContext) val renderersFactory = DefaultRenderersFactory(requireContext().applicationContext)
.setEnableDecoderFallback(true) .setEnableDecoderFallback(true)
.setExtensionRendererMode(EXTENSION_RENDERER_MODE_PREFER) .setExtensionRendererMode(EXTENSION_RENDERER_MODE_PREFER)
.setMediaCodecSelector { mimeType, requiresSecureDecoder, requiresTunnelingDecoder -> .setMediaCodecSelector { mimeType, requiresSecureDecoder, requiresTunnelingDecoder ->
var decoderInfos: MutableList<MediaCodecInfo> = var decoderInfo: MutableList<MediaCodecInfo> =
MediaCodecSelector.DEFAULT MediaCodecSelector.DEFAULT
.getDecoderInfos( .getDecoderInfos(
mimeType, mimeType,
@ -122,13 +122,13 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
) )
if (MimeTypes.VIDEO_H264 == mimeType) { if (MimeTypes.VIDEO_H264 == mimeType) {
// copy the list because MediaCodecSelector.DEFAULT returns an unmodifiable list // copy the list because MediaCodecSelector.DEFAULT returns an unmodifiable list
decoderInfos = ArrayList(decoderInfos) decoderInfo = ArrayList(decoderInfo)
decoderInfos.reverse() decoderInfo.reverse()
} }
decoderInfos decoderInfo
} }
val trackSelector = DefaultTrackSelector() val trackSelector = DefaultTrackSelector(requireContext())
val loadControl = DefaultLoadControl() val loadControl = DefaultLoadControl()
player = ExoPlayer.Builder(requireContext(), renderersFactory) player = ExoPlayer.Builder(requireContext(), renderersFactory)
@ -136,7 +136,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
.setLoadControl(loadControl) .setLoadControl(loadControl)
.build() .build()
val frame = view.findViewById<MaterialCardView>(R.id.frame_layout) val frame = view.findViewById<MaterialCardView>(R.id.frame_layout)
val videoView = view.findViewById<PlayerView>(R.id.video_view) val videoView = view.findViewById<StyledPlayerView>(R.id.video_view)
videoView.player = player videoView.player = player
timeSeconds = convertStringToTimestamp(item.duration) timeSeconds = convertStringToTimestamp(item.duration)
chapters = emptyList() chapters = emptyList()
@ -207,9 +207,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
progress.visibility = View.GONE progress.visibility = View.GONE
populateSuggestedChapters() populateSuggestedChapters()
player.prepare() player.prepare().apply {
player.seekTo((((rangeSlider.valueFrom.toInt() * timeSeconds) / 100) * 1000).toLong()) player.play()
player.play() }
}catch (e: Exception){ }catch (e: Exception){
progress.visibility = View.GONE progress.visibility = View.GONE
frame.visibility = View.GONE frame.visibility = View.GONE
@ -253,11 +253,12 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
} }
@SuppressLint("SetTextI18n")
private fun initCutSection(){ private fun initCutSection(){
fromTextInput.editText!!.setText("0:00") fromTextInput.editText!!.setText("0:00")
toTextInput.editText!!.setText(item.duration) toTextInput.editText!!.setText(item.duration)
rangeSlider.addOnChangeListener { rangeSlider, value, fromUser -> rangeSlider.addOnChangeListener { rangeSlider, _, _ ->
val values = rangeSlider.values val values = rangeSlider.values
val startTimestamp = (values[0].toInt() * timeSeconds) / 100 val startTimestamp = (values[0].toInt() * timeSeconds) / 100
val endTimestamp = (values[1].toInt() * timeSeconds) / 100 val endTimestamp = (values[1].toInt() * timeSeconds) / 100
@ -304,9 +305,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
val startValueTimeStampSeconds = (startValue.toInt() * timeSeconds) / 100 val startValueTimeStampSeconds = (startValue.toInt() * timeSeconds) / 100
fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startValueTimeStampSeconds, Locale.US)) fromTextInput.editText!!.setText(infoUtil.formatIntegerDuration(startValueTimeStampSeconds, Locale.US))
return true; return true
} }
return false; return false
} }
}) })
@ -336,9 +337,9 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
val endValueTimeStampSeconds = (endValue.toInt() * timeSeconds) / 100 val endValueTimeStampSeconds = (endValue.toInt() * timeSeconds) / 100
toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endValueTimeStampSeconds, Locale.US)) toTextInput.editText!!.setText(infoUtil.formatIntegerDuration(endValueTimeStampSeconds, Locale.US))
return true; return true
} }
return false; return false
} }
}) })
@ -409,7 +410,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
if (item.downloadSections.isNotBlank()){ if (item.downloadSections.isNotBlank()){
chipGroup.removeAllViews() chipGroup.removeAllViews()
item.downloadSections.split(";").forEachIndexed { index, it -> item.downloadSections.split(";").forEachIndexed { _, it ->
if (it.isBlank()) return if (it.isBlank()) return
if (it.contains(":")) createChip(it.replace(";", "")) if (it.contains(":")) createChip(it.replace(";", ""))
else createChapterChip(ChapterItem(0, 0, it), null) else createChapterChip(ChapterItem(0, 0, it), null)
@ -436,7 +437,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list
if (chip.isChecked) { if (chip.isChecked) {
rangeSlider.setValues(startingValue.toFloat(), endingValue.toFloat()) rangeSlider.setValues(startingValue.toFloat(), endingValue.toFloat())
player.prepare() player.prepare()
player.seekTo((((startingValue * timeSeconds) / 100) * 1000).toLong()) player.seekTo((startTimestamp * 1000).toLong())
player.play() player.play()
}else { }else {
player.seekTo(0) player.seekTo(0)

View file

@ -71,7 +71,7 @@ class DownloadBottomSheetDialog(private val resultItem: ResultItem, private val
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels behavior.state = BottomSheetBehavior.STATE_EXPANDED
} }

View file

@ -69,12 +69,6 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
uiUtil = UiUtil(fileUtil) uiUtil = UiUtil(fileUtil)
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val behavior = BottomSheetBehavior.from(view.parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@SuppressLint("RestrictedApi", "NotifyDataSetChanged") @SuppressLint("RestrictedApi", "NotifyDataSetChanged")
override fun setupDialog(dialog: Dialog, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style) super.setupDialog(dialog, style)
@ -85,7 +79,7 @@ class DownloadMultipleBottomSheetDialog(private var results: List<ResultItem?>,
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels / 2 behavior.state = BottomSheetBehavior.STATE_EXPANDED
} }
listAdapter = listAdapter =

View file

@ -178,8 +178,10 @@ class DownloadVideoFragment(private val resultItem: ResultItem, private var curr
containers containers
) )
) )
downloadItem.format.container = containerPreference!! downloadItem.format.container = if (containerPreference == getString(R.string.defaultValue)) "" else containerPreference!!
containerAutoCompleteTextView!!.setText(downloadItem.format.container, false) containerAutoCompleteTextView!!.setText(
downloadItem.format.container.ifEmpty { getString(R.string.defaultValue) },
false)
(container!!.editText as AutoCompleteTextView?)!!.onItemClickListener = (container!!.editText as AutoCompleteTextView?)!!.onItemClickListener =
AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long -> AdapterView.OnItemClickListener { _: AdapterView<*>?, _: View?, index: Int, _: Long ->

View file

@ -45,12 +45,6 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java] resultViewModel = ViewModelProvider(this)[ResultViewModel::class.java]
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val behavior = BottomSheetBehavior.from(view.parent as View)
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
@SuppressLint("RestrictedApi") @SuppressLint("RestrictedApi")
override fun setupDialog(dialog: Dialog, style: Int) { override fun setupDialog(dialog: Dialog, style: Int) {
super.setupDialog(dialog, style) super.setupDialog(dialog, style)
@ -61,7 +55,7 @@ class SelectPlaylistItemsBottomSheetDialog(private val items: List<ResultItem?>,
behavior = BottomSheetBehavior.from(view.parent as View) behavior = BottomSheetBehavior.from(view.parent as View)
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
behavior.peekHeight = displayMetrics.heightPixels / 2 behavior.state = BottomSheetBehavior.STATE_EXPANDED
} }
listAdapter = listAdapter =

View file

@ -358,6 +358,7 @@ class HistoryFragment : Fragment(), HistoryAdapter.OnItemClickListener{
//val websites = historyRecyclerViewAdapter!!.websites //val websites = historyRecyclerViewAdapter!!.websites
for (i in websites.indices) { for (i in websites.indices) {
val w = websites[i] val w = websites[i]
if (w == "null" || w.isEmpty()) continue
val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip val tmp = layoutinflater!!.inflate(R.layout.filter_chip, websiteGroup, false) as Chip
tmp.text = w tmp.text = w
tmp.id = i tmp.id = i

View file

@ -256,6 +256,13 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString()) WorkManager.getInstance(requireContext()).cancelUniqueWork(id.toString())
notificationUtil.cancelDownloadNotification(id) notificationUtil.cancelDownloadNotification(id)
downloadViewModel.deleteDownload(item!!) downloadViewModel.deleteDownload(item!!)
Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + item.title, Snackbar.LENGTH_LONG)
.setAction(getString(R.string.undo)) {
lifecycleScope.launch(Dispatchers.IO) {
downloadViewModel.queueDownloads(listOf(item))
}
}.show()
} }
deleteDialog.show() deleteDialog.show()
} }
@ -273,12 +280,6 @@ class QueuedDownloadsFragment : Fragment(), GenericDownloadAdapter.OnItemClickLi
ItemTouchHelper.LEFT -> { ItemTouchHelper.LEFT -> {
val deletedItem = items[position] val deletedItem = items[position]
removeItem(deletedItem.id) removeItem(deletedItem.id)
Snackbar.make(queuedRecyclerView, getString(R.string.cancelled) + ": " + deletedItem.title, Snackbar.LENGTH_LONG)
.setAction(getString(R.string.undo)) {
lifecycleScope.launch(Dispatchers.IO) {
downloadViewModel.queueDownloads(listOf(deletedItem))
}
}.show()
} }
} }

View file

@ -7,16 +7,11 @@ import android.os.Looper
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.R
import com.deniscerri.ytdlnis.database.models.DownloadItem
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.ResultItem import com.deniscerri.ytdlnis.database.models.ResultItem
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.google.gson.reflect.TypeToken
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest import com.yausername.youtubedl_android.YoutubeDLRequest
import kotlinx.serialization.json.Json
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
@ -137,7 +132,7 @@ class InfoUtil(private val context: Context) {
"thumb", "thumb",
element.getJSONArray("videoThumbnails").getJSONObject(0).getString("url") element.getJSONArray("videoThumbnails").getJSONObject(0).getString("url")
) )
val v = createVideofromInvidiousJSON(element) val v = createVideoFromInvidiousJSON(element)
if (v == null || v.thumb.isEmpty()) { if (v == null || v.thumb.isEmpty()) {
continue continue
} }
@ -225,7 +220,7 @@ class InfoUtil(private val context: Context) {
val vids = res.getJSONArray("videos") val vids = res.getJSONArray("videos")
for (i in 0 until vids.length()) { for (i in 0 until vids.length()) {
val element = vids.getJSONObject(i) val element = vids.getJSONObject(i)
val v = createVideofromInvidiousJSON(element) val v = createVideoFromInvidiousJSON(element)
if (v == null || v.thumb.isEmpty()) continue if (v == null || v.thumb.isEmpty()) continue
v.playlistTitle = res.getString("title") v.playlistTitle = res.getString("title")
items.add(v) items.add(v)
@ -243,7 +238,7 @@ class InfoUtil(private val context: Context) {
if (key!!.isEmpty()) { if (key!!.isEmpty()) {
return if (useInvidous) { return if (useInvidous) {
val res = genericRequest(invidousURL + "videos/" + id) val res = genericRequest(invidousURL + "videos/" + id)
if (res.length() == 0) getFromYTDL("https://www.youtube.com/watch?v=$id")[0] else createVideofromInvidiousJSON( if (res.length() == 0) getFromYTDL("https://www.youtube.com/watch?v=$id")[0] else createVideoFromInvidiousJSON(
res res
) )
} else { } else {
@ -293,7 +288,7 @@ class InfoUtil(private val context: Context) {
return video return video
} }
private fun createVideofromInvidiousJSON(obj: JSONObject): ResultItem? { private fun createVideoFromInvidiousJSON(obj: JSONObject): ResultItem? {
var video: ResultItem? = null var video: ResultItem? = null
try { try {
val id = obj.getString("videoId") val id = obj.getString("videoId")
@ -476,7 +471,7 @@ class InfoUtil(private val context: Context) {
for (i in 0 until res.length()) { for (i in 0 until res.length()) {
val element = res.getJSONObject(i) val element = res.getJSONObject(i)
if (element.getString("type") != "video") continue if (element.getString("type") != "video") continue
val v = createVideofromInvidiousJSON(element) val v = createVideoFromInvidiousJSON(element)
if (v == null || v.thumb.isEmpty()) continue if (v == null || v.thumb.isEmpty()) continue
v.playlistTitle = context.getString(R.string.trendingPlaylist) v.playlistTitle = context.getString(R.string.trendingPlaylist)
items.add(v) items.add(v)
@ -513,7 +508,7 @@ class InfoUtil(private val context: Context) {
val id = getIDFromYoutubeURL(url) val id = getIDFromYoutubeURL(url)
val res = genericRequest(invidousURL + "videos/" + id) val res = genericRequest(invidousURL + "videos/" + id)
if (res.length() == 0) getFromYTDL(url)[0]!! if (res.length() == 0) getFromYTDL(url)[0]!!
else createVideofromInvidiousJSON( else createVideoFromInvidiousJSON(
res res
)!! )!!
}else{ }else{
@ -691,8 +686,29 @@ class InfoUtil(private val context: Context) {
val youtubeDLResponse = YoutubeDL.getInstance().execute(request) val youtubeDLResponse = YoutubeDL.getInstance().execute(request)
val jsonObject = JSONObject(youtubeDLResponse.out) val jsonObject = JSONObject(youtubeDLResponse.out)
val thumbs = jsonObject.getJSONArray("thumbnails")
val thumb = thumbs.getJSONObject(thumbs.length() - 1).getString("url") var author: String? = ""
if (jsonObject.has("uploader")) {
author = jsonObject.getString("uploader")
}
var duration = ""
runCatching {
if (jsonObject.has("duration")) {
duration = formatIntegerDuration(jsonObject.getInt("duration"), Locale.getDefault())
}
}
var thumb: String? = ""
if (jsonObject.has("thumbnail")) {
thumb = jsonObject.getString("thumbnail")
} else if (jsonObject.has("thumbnails")) {
val thumbs = jsonObject.getJSONArray("thumbnails")
if (thumbs.length() > 0){
thumb = thumbs.getJSONObject(thumbs.length() - 1).getString("url")
}
}
val isPlaylist = jsonObject.has("playlist_count") val isPlaylist = jsonObject.has("playlist_count")
return ResultItem( return ResultItem(
0, 0,
@ -702,9 +718,9 @@ class InfoUtil(private val context: Context) {
}else{ }else{
jsonObject.getString("title") jsonObject.getString("title")
}, },
jsonObject.getString("uploader"), author!!,
if (jsonObject.has("duration")) formatIntegerDuration(jsonObject.getInt("duration"), Locale.US) else "", duration,
thumb, thumb!!,
jsonObject.getString("extractor"), jsonObject.getString("extractor"),
if (isPlaylist) jsonObject.getString("title") else "", if (isPlaylist) jsonObject.getString("title") else "",
arrayListOf(), arrayListOf(),

View file

@ -8,6 +8,7 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.text.Editable import android.text.Editable
import android.text.TextWatcher import android.text.TextWatcher
import android.util.DisplayMetrics
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -28,6 +29,7 @@ import com.deniscerri.ytdlnis.database.models.CommandTemplate
import com.deniscerri.ytdlnis.database.models.Format import com.deniscerri.ytdlnis.database.models.Format
import com.deniscerri.ytdlnis.database.models.TemplateShortcut import com.deniscerri.ytdlnis.database.models.TemplateShortcut
import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel import com.deniscerri.ytdlnis.database.viewmodel.CommandTemplateViewModel
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.chip.Chip import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup import com.google.android.material.chip.ChipGroup
@ -154,6 +156,7 @@ class UiUtil(private val fileUtil: FileUtil) {
} }
bottomSheet.show() bottomSheet.show()
bottomSheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT
@ -195,6 +198,7 @@ class UiUtil(private val fileUtil: FileUtil) {
} }
bottomSheet.show() bottomSheet.show()
bottomSheet.behavior.state = BottomSheetBehavior.STATE_EXPANDED
bottomSheet.window!!.setLayout( bottomSheet.window!!.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT ViewGroup.LayoutParams.MATCH_PARENT

View file

@ -23,6 +23,8 @@ import com.deniscerri.ytdlnis.util.NotificationUtil
import com.yausername.youtubedl_android.YoutubeDL import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLRequest import com.yausername.youtubedl_android.YoutubeDLRequest
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.File import java.io.File
@ -45,6 +47,7 @@ class DownloadWorker(
val dao = dbManager.downloadDao val dao = dbManager.downloadDao
val repository = DownloadRepository(dao) val repository = DownloadRepository(dao)
val historyDao = dbManager.historyDao val historyDao = dbManager.historyDao
val resultDao = dbManager.resultDao
val handler = Handler(Looper.getMainLooper()) val handler = Handler(Looper.getMainLooper())
@ -152,7 +155,7 @@ class DownloadWorker(
else if (audioQualityId == context.getString(R.string.worst_quality)) audioQualityId = "worstaudio" else if (audioQualityId == context.getString(R.string.worst_quality)) audioQualityId = "worstaudio"
val ext = downloadItem.format.container val ext = downloadItem.format.container
if (audioQualityId.isBlank() || ext == "Default" || ext == context.getString(R.string.defaultValue)) request.addOption("-x") if (audioQualityId.isBlank()) request.addOption("-x")
else request.addOption("-f", audioQualityId) else request.addOption("-f", audioQualityId)
if(ext != "webm"){ if(ext != "webm"){
@ -224,7 +227,7 @@ class DownloadWorker(
Log.e(TAG, formatArgument) Log.e(TAG, formatArgument)
request.addOption("-f", formatArgument) request.addOption("-f", formatArgument)
val format = downloadItem.format.container val format = downloadItem.format.container
if(format.isNotEmpty() && format != "Default" && format != context.getString(R.string.defaultValue)){ if(format.isNotEmpty()){
request.addOption("--merge-output-format", format) request.addOption("--merge-output-format", format)
if (format != "webm") { if (format != "webm") {
val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false) val embedThumb = sharedPreferences.getBoolean("embed_thumbnail", false)
@ -267,7 +270,7 @@ class DownloadWorker(
} }
} }
var wasQuickDownloaded = false
//update item if its incomplete //update item if its incomplete
if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){ if (downloadItem.title.isEmpty() || downloadItem.author.isEmpty() || downloadItem.thumb.isEmpty()){
runCatching { runCatching {
@ -275,10 +278,11 @@ class DownloadWorker(
val info = infoUtil.getMissingInfo(downloadItem.url) val info = infoUtil.getMissingInfo(downloadItem.url)
if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString() if (downloadItem.title.isEmpty()) downloadItem.title = info?.title.toString()
if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString() if (downloadItem.author.isEmpty()) downloadItem.author = info?.author.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
downloadItem.duration = info?.duration.toString() downloadItem.duration = info?.duration.toString()
downloadItem.website = info?.website.toString() downloadItem.website = info?.website.toString()
if (downloadItem.thumb.isEmpty()) downloadItem.thumb = info?.thumb.toString()
runBlocking { runBlocking {
wasQuickDownloaded = resultDao.getCountInt() == 0
dao.update(downloadItem) dao.update(downloadItem)
} }
} }
@ -345,6 +349,19 @@ class DownloadWorker(
NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID NotificationUtil.DOWNLOAD_FINISHED_CHANNEL_ID
) )
if (wasQuickDownloaded){
runCatching {
setProgressAsync(workDataOf("progress" to 100, "output" to "Creating Result Items", "id" to downloadItem.id, "log" to false))
runBlocking {
infoUtil.getFromYTDL(downloadItem.url).forEach { res ->
if (res != null) {
resultDao.insert(res)
}
}
}
}
}
runBlocking { runBlocking {
dao.delete(downloadItem.id) dao.delete(downloadItem.id)
} }

View file

@ -64,7 +64,7 @@ class TerminalDownloadWorker(
request.addOption("--cookies", cookiesFile.absolutePath) request.addOption("--cookies", cookiesFile.absolutePath)
} }
if (!command.contains("-P ")) request.addOption("-P", tempFileDir.absolutePath) request.addOption("-P", tempFileDir.absolutePath)
val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false) val logDownloads = sharedPreferences.getBoolean("log_downloads", false) && !sharedPreferences.getBoolean("incognito", false)
val logFolder = File(context.filesDir.absolutePath + "/logs") val logFolder = File(context.filesDir.absolutePath + "/logs")

View file

@ -15,7 +15,7 @@
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" > app:layout_constraintTop_toTopOf="parent" >
<com.google.android.exoplayer2.ui.PlayerView <com.google.android.exoplayer2.ui.StyledPlayerView
android:id="@+id/video_view" android:id="@+id/video_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -15,5 +15,5 @@
android:id="@+id/folder" android:id="@+id/folder"
android:title="@string/command_directory" android:title="@string/command_directory"
android:icon="@drawable/baseline_folder_24" android:icon="@drawable/baseline_folder_24"
app:showAsAction="collapseActionView|ifRoom"/> app:showAsAction="ifRoom"/>
</menu> </menu>

View file

@ -11,7 +11,7 @@
</string-array> </string-array>
<string-array name="audio_containers_values"> <string-array name="audio_containers_values">
<item>Default</item> <item />
<item>mp3</item> <item>mp3</item>
<item>m4a</item> <item>m4a</item>
<item>aac</item> <item>aac</item>
@ -29,7 +29,7 @@
</string-array> </string-array>
<string-array name="video_containers_values"> <string-array name="video_containers_values">
<item>Default</item> <item />
<item>mp4</item> <item>mp4</item>
<item>mkv</item> <item>mkv</item>
<item>webm</item> <item>webm</item>
@ -96,6 +96,7 @@
<item>tr</item> <item>tr</item>
<item>uk</item> <item>uk</item>
<item>vi</item> <item>vi</item>
<item>zh</item>
</string-array> </string-array>

View file

@ -1,11 +1,8 @@
<resources xmlns:tools="http://schemas.android.com/tools"> <resources xmlns:tools="http://schemas.android.com/tools">
<style name="BaseTheme" parent="Theme.Material3.Light.NoActionBar"> <style name="BaseTheme" parent="Theme.Material3.Light.NoActionBar">
<item name="android:windowLightStatusBar">?attr/isLightTheme</item> <item name="android:windowLightStatusBar">?attr/isLightTheme</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">@android:color/transparent</item> <item name="android:statusBarColor">@android:color/transparent</item>
<item name="windowActionModeOverlay">true</item>
<item name="alertDialogTheme">@style/ThemeOverlay.Material3.MaterialAlertDialog</item> <item name="alertDialogTheme">@style/ThemeOverlay.Material3.MaterialAlertDialog</item>
<item name="dialogCornerRadius">28dp</item> <item name="dialogCornerRadius">28dp</item>
<item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat.Material3</item> <item name="switchPreferenceCompatStyle">@style/Preference.SwitchPreferenceCompat.Material3</item>

View file

@ -18,4 +18,5 @@
<locale android:name="tr-TR"/> <locale android:name="tr-TR"/>
<locale android:name="uk"/> <locale android:name="uk"/>
<locale android:name="vi"/> <locale android:name="vi"/>
<locale android:name="zh-CN"/>
</locale-config> </locale-config>

View file

@ -6,7 +6,10 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
android.defaults.buildfeatures.buildconfig=true
android.enableJetifier=true android.enableJetifier=true
android.nonFinalResIds=false
android.nonTransitiveRClass=false
android.useAndroidX=true android.useAndroidX=true
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.