mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-29 08:20:32 +05:30
Merge pull request #4818 from Bnyro/master
feat: parse YouTube links in the search bar
This commit is contained in:
commit
797a7ceec9
@ -30,7 +30,8 @@ import com.github.libretube.util.TextUtils
|
|||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
|
|
||||||
class SearchAdapter(
|
class SearchAdapter(
|
||||||
private val isChannelAdapter: Boolean = false
|
private val isChannelAdapter: Boolean = false,
|
||||||
|
private val timeStamp: Long = 0,
|
||||||
) : ListAdapter<ContentItem, SearchViewHolder>(SearchCallback) {
|
) : ListAdapter<ContentItem, SearchViewHolder>(SearchCallback) {
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SearchViewHolder {
|
||||||
val layoutInflater = LayoutInflater.from(parent.context)
|
val layoutInflater = LayoutInflater.from(parent.context)
|
||||||
@ -97,7 +98,7 @@ class SearchAdapter(
|
|||||||
ImageHelper.loadImage(item.uploaderAvatar, channelImage)
|
ImageHelper.loadImage(item.uploaderAvatar, channelImage)
|
||||||
}
|
}
|
||||||
root.setOnClickListener {
|
root.setOnClickListener {
|
||||||
NavigationHelper.navigateVideo(root.context, item.url)
|
NavigationHelper.navigateVideo(root.context, item.url, timestamp = timeStamp)
|
||||||
}
|
}
|
||||||
val videoId = item.url.toID()
|
val videoId = item.url.toID()
|
||||||
|
|
||||||
|
@ -1129,7 +1129,7 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
*/
|
*/
|
||||||
private fun handleLink(link: String) {
|
private fun handleLink(link: String) {
|
||||||
// get video id if the link is a valid youtube video link
|
// get video id if the link is a valid youtube video link
|
||||||
val videoId = TextUtils.getVideoIdFromUri(link)
|
val videoId = TextUtils.getVideoIdFromUrl(link)
|
||||||
if (videoId.isNullOrEmpty()) {
|
if (videoId.isNullOrEmpty()) {
|
||||||
// not a YouTube video link, thus handle normally
|
// not a YouTube video link, thus handle normally
|
||||||
val intent = Intent(Intent.ACTION_VIEW, link.toUri())
|
val intent = Intent(Intent.ACTION_VIEW, link.toUri())
|
||||||
|
@ -21,13 +21,18 @@ import com.github.libretube.db.DatabaseHelper
|
|||||||
import com.github.libretube.db.obj.SearchHistoryItem
|
import com.github.libretube.db.obj.SearchHistoryItem
|
||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.extensions.hideKeyboard
|
import com.github.libretube.extensions.hideKeyboard
|
||||||
|
import com.github.libretube.extensions.toID
|
||||||
import com.github.libretube.extensions.toastFromMainDispatcher
|
import com.github.libretube.extensions.toastFromMainDispatcher
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
import com.github.libretube.ui.adapters.SearchAdapter
|
import com.github.libretube.ui.adapters.SearchAdapter
|
||||||
|
import com.github.libretube.ui.dialogs.ShareDialog
|
||||||
|
import com.github.libretube.util.TextUtils
|
||||||
|
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
||||||
import com.github.libretube.util.deArrow
|
import com.github.libretube.util.deArrow
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
|
|
||||||
class SearchResultFragment : Fragment() {
|
class SearchResultFragment : Fragment() {
|
||||||
private var _binding: FragmentSearchResultBinding? = null
|
private var _binding: FragmentSearchResultBinding? = null
|
||||||
@ -37,7 +42,7 @@ class SearchResultFragment : Fragment() {
|
|||||||
private var query = ""
|
private var query = ""
|
||||||
|
|
||||||
private lateinit var searchAdapter: SearchAdapter
|
private lateinit var searchAdapter: SearchAdapter
|
||||||
private var apiSearchFilter = "all"
|
private var searchFilter = "all"
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -63,7 +68,7 @@ class SearchResultFragment : Fragment() {
|
|||||||
|
|
||||||
// filter options
|
// filter options
|
||||||
binding.filterChipGroup.setOnCheckedStateChangeListener { _, _ ->
|
binding.filterChipGroup.setOnCheckedStateChangeListener { _, _ ->
|
||||||
apiSearchFilter = when (
|
searchFilter = when (
|
||||||
binding.filterChipGroup.checkedChipId
|
binding.filterChipGroup.checkedChipId
|
||||||
) {
|
) {
|
||||||
R.id.chip_all -> "all"
|
R.id.chip_all -> "all"
|
||||||
@ -95,11 +100,20 @@ class SearchResultFragment : Fragment() {
|
|||||||
_binding?.searchResultsLayout?.isGone = true
|
_binding?.searchResultsLayout?.isGone = true
|
||||||
|
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
|
var timeStamp: Long? = null
|
||||||
|
|
||||||
|
// parse search URLs from YouTube entered in the search bar
|
||||||
|
val searchQuery = query.toHttpUrlOrNull()?.let {
|
||||||
|
val videoId = TextUtils.getVideoIdFromUrl(it.toString()) ?: query
|
||||||
|
timeStamp = it.queryParameter("t")?.toTimeInSeconds()
|
||||||
|
"${ShareDialog.YOUTUBE_FRONTEND_URL}/watch?v=${videoId}"
|
||||||
|
} ?: query
|
||||||
|
|
||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||||
view?.let { context?.hideKeyboard(it) }
|
view?.let { context?.hideKeyboard(it) }
|
||||||
val response = try {
|
val response = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getSearchResults(query, apiSearchFilter).apply {
|
RetrofitInstance.api.getSearchResults(searchQuery, searchFilter).apply {
|
||||||
items = items.deArrow()
|
items = items.deArrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,9 +124,10 @@ class SearchResultFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val binding = _binding ?: return@repeatOnLifecycle
|
val binding = _binding ?: return@repeatOnLifecycle
|
||||||
searchAdapter = SearchAdapter()
|
searchAdapter = SearchAdapter(timeStamp = timeStamp ?: 0)
|
||||||
binding.searchRecycler.adapter = searchAdapter
|
binding.searchRecycler.adapter = searchAdapter
|
||||||
searchAdapter.submitList(response.items)
|
searchAdapter.submitList(response.items)
|
||||||
|
|
||||||
binding.searchResultsLayout.isVisible = true
|
binding.searchResultsLayout.isVisible = true
|
||||||
binding.progress.isGone = true
|
binding.progress.isGone = true
|
||||||
binding.noSearchResult.isVisible = response.items.isEmpty()
|
binding.noSearchResult.isVisible = response.items.isEmpty()
|
||||||
@ -129,7 +144,7 @@ class SearchResultFragment : Fragment() {
|
|||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getSearchResultsNextPage(
|
RetrofitInstance.api.getSearchResultsNextPage(
|
||||||
query,
|
query,
|
||||||
apiSearchFilter,
|
searchFilter,
|
||||||
nextPage!!
|
nextPage!!
|
||||||
).apply {
|
).apply {
|
||||||
items = items.deArrow()
|
items = items.deArrow()
|
||||||
|
@ -52,10 +52,10 @@ object TextUtils {
|
|||||||
/**
|
/**
|
||||||
* Get video id if the link is a valid youtube video link
|
* Get video id if the link is a valid youtube video link
|
||||||
*/
|
*/
|
||||||
fun getVideoIdFromUri(link: String): String? {
|
fun getVideoIdFromUrl(link: String): String? {
|
||||||
return link.toHttpUrlOrNull()?.let {
|
return link.toHttpUrlOrNull()?.let {
|
||||||
when (it.host) {
|
when (it.host) {
|
||||||
"www.youtube.com" -> it.queryParameter("v")
|
"www.youtube.com", "m.youtube.com" -> it.queryParameter("v")
|
||||||
"youtu.be" -> it.pathSegments.lastOrNull()
|
"youtu.be" -> it.pathSegments.lastOrNull()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user