mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-14 22:30:30 +05:30
Merge pull request #2442 from Bnyro/master
Improve the playlist cloning algorithm
This commit is contained in:
commit
b98e6f5965
@ -6,6 +6,7 @@ import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.Playlist
|
||||
import com.github.libretube.api.obj.PlaylistId
|
||||
import com.github.libretube.api.obj.Playlists
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.constants.YOUTUBE_FRONTEND_URL
|
||||
import com.github.libretube.db.DatabaseHolder
|
||||
import com.github.libretube.db.obj.LocalPlaylist
|
||||
@ -19,13 +20,13 @@ import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.obj.ImportPlaylist
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.github.libretube.util.ProxyHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
object PlaylistsHelper {
|
||||
private val pipedPlaylistRegex = "[\\da-fA-F]{8}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{12}".toRegex()
|
||||
@ -110,16 +111,17 @@ object PlaylistsHelper {
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videoIds: String): Boolean {
|
||||
suspend fun addToPlaylist(playlistId: String, vararg videos: StreamItem): Boolean {
|
||||
if (!loggedIn) {
|
||||
val localPlaylist = DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
.first { it.playlist.id.toString() == playlistId }
|
||||
|
||||
for (videoId in videoIds) {
|
||||
val localPlaylistItem = RetrofitInstance.api.getStreams(videoId).toLocalPlaylistItem(playlistId, videoId)
|
||||
for (video in videos) {
|
||||
val localPlaylistItem = video.toLocalPlaylistItem(playlistId)
|
||||
awaitQuery {
|
||||
// avoid duplicated videos in a playlist
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByVideoId(playlistId, videoId)
|
||||
DatabaseHolder.Database.localPlaylistsDao()
|
||||
.deletePlaylistItemsByVideoId(playlistId, localPlaylistItem.videoId)
|
||||
|
||||
// add the new video to the database
|
||||
DatabaseHolder.Database.localPlaylistsDao().addPlaylistVideo(localPlaylistItem)
|
||||
@ -128,7 +130,9 @@ object PlaylistsHelper {
|
||||
// set the new playlist thumbnail URL
|
||||
localPlaylistItem.thumbnailUrl?.let {
|
||||
localPlaylist.playlist.thumbnailUrl = it
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(localPlaylist.playlist)
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(
|
||||
localPlaylist.playlist
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -140,7 +144,7 @@ object PlaylistsHelper {
|
||||
token,
|
||||
PlaylistId(
|
||||
playlistId = playlistId,
|
||||
videoIds = videoIds.toList()
|
||||
videoIds = videos.toList().map { it.url!!.toID() }
|
||||
)
|
||||
).message == "ok"
|
||||
}
|
||||
@ -172,13 +176,19 @@ object PlaylistsHelper {
|
||||
DatabaseHolder.Database.localPlaylistsDao().getAll()
|
||||
}.first { it.playlist.id.toString() == playlistId }
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(transaction.videos[index])
|
||||
DatabaseHolder.Database.localPlaylistsDao().removePlaylistVideo(
|
||||
transaction.videos[index]
|
||||
)
|
||||
}
|
||||
if (transaction.videos.size > 1) {
|
||||
if (index == 0) {
|
||||
transaction.videos[1].thumbnailUrl?.let { transaction.playlist.thumbnailUrl = it }
|
||||
transaction.videos[1].thumbnailUrl?.let {
|
||||
transaction.playlist.thumbnailUrl = it
|
||||
}
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(transaction.playlist)
|
||||
DatabaseHolder.Database.localPlaylistsDao().updatePlaylist(
|
||||
transaction.playlist
|
||||
)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -203,11 +213,27 @@ object PlaylistsHelper {
|
||||
suspend fun importPlaylists(appContext: Context, playlists: List<ImportPlaylist>) {
|
||||
for (playlist in playlists) {
|
||||
val playlistId = createPlaylist(playlist.name!!, appContext) ?: continue
|
||||
addToPlaylist(
|
||||
playlistId,
|
||||
*playlist.videos.map {
|
||||
it.substring(it.length - 11, it.length)
|
||||
}.toTypedArray()
|
||||
// if logged in, add the playlists by their ID via an api call
|
||||
val success: Boolean = if (loggedIn) {
|
||||
addToPlaylist(
|
||||
playlistId,
|
||||
*playlist.videos.map {
|
||||
StreamItem(url = it)
|
||||
}.toTypedArray()
|
||||
)
|
||||
} else {
|
||||
// if not logged in, all video information needs to become fetched manually
|
||||
try {
|
||||
val streamItems = playlist.videos.map {
|
||||
RetrofitInstance.api.getStreams(it).toStreamItem(it)
|
||||
}
|
||||
addToPlaylist(playlistId, *streamItems.toTypedArray())
|
||||
} catch (e: Exception) {
|
||||
false
|
||||
}
|
||||
}
|
||||
appContext.toastFromMainThread(
|
||||
if (success) R.string.importsuccess else R.string.server_error
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -253,9 +279,7 @@ object PlaylistsHelper {
|
||||
|
||||
addToPlaylist(
|
||||
newPlaylist,
|
||||
*playlist.relatedStreams.orEmpty()
|
||||
.map { it.url!!.toID() }
|
||||
.toTypedArray()
|
||||
*playlist.relatedStreams.orEmpty().toTypedArray()
|
||||
)
|
||||
|
||||
var nextPage = playlist.nextpage
|
||||
@ -264,9 +288,7 @@ object PlaylistsHelper {
|
||||
RetrofitInstance.api.getPlaylistNextPage(playlistId, nextPage).apply {
|
||||
addToPlaylist(
|
||||
newPlaylist,
|
||||
*relatedStreams.orEmpty()
|
||||
.map { it.url!!.toID() }
|
||||
.toTypedArray()
|
||||
*relatedStreams.orEmpty().toTypedArray()
|
||||
)
|
||||
}.nextpage
|
||||
} catch (e: Exception) {
|
||||
|
@ -61,7 +61,12 @@ object SubscriptionHelper {
|
||||
}
|
||||
}
|
||||
|
||||
fun handleUnsubscribe(context: Context, channelId: String, channelName: String?, onUnsubscribe: () -> Unit) {
|
||||
fun handleUnsubscribe(
|
||||
context: Context,
|
||||
channelId: String,
|
||||
channelName: String?,
|
||||
onUnsubscribe: () -> Unit
|
||||
) {
|
||||
if (!PreferenceHelper.getBoolean(PreferenceKeys.CONFIRM_UNSUBSCRIBE, false)) {
|
||||
unsubscribe(channelId)
|
||||
onUnsubscribe.invoke()
|
||||
|
@ -4,6 +4,8 @@ import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
fun Float.round(decimalPlaces: Int): Float {
|
||||
return (this * 10.0.pow(decimalPlaces.toDouble())).roundToInt() / 10.0.pow(decimalPlaces.toDouble())
|
||||
return (this * 10.0.pow(decimalPlaces.toDouble())).roundToInt() / 10.0.pow(
|
||||
decimalPlaces.toDouble()
|
||||
)
|
||||
.toFloat()
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
package com.github.libretube.extensions
|
||||
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.db.obj.LocalPlaylistItem
|
||||
|
||||
fun Streams.toLocalPlaylistItem(playlistId: String, videoId: String): LocalPlaylistItem {
|
||||
fun StreamItem.toLocalPlaylistItem(playlistId: String): LocalPlaylistItem {
|
||||
return LocalPlaylistItem(
|
||||
playlistId = playlistId.toInt(),
|
||||
videoId = videoId,
|
||||
videoId = url!!.toID(),
|
||||
title = title,
|
||||
thumbnailUrl = thumbnailUrl,
|
||||
uploader = uploader,
|
||||
thumbnailUrl = thumbnail,
|
||||
uploader = uploaderName,
|
||||
uploaderUrl = uploaderUrl,
|
||||
uploaderAvatar = uploaderAvatar,
|
||||
uploadDate = uploadDate,
|
||||
uploadDate = uploadedDate,
|
||||
duration = duration
|
||||
)
|
||||
}
|
||||
|
@ -80,7 +80,9 @@ class UpdateService : Service() {
|
||||
}
|
||||
|
||||
private fun getDownloadDirectory(): File {
|
||||
val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||
val downloadsDir = Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS
|
||||
)
|
||||
if (!downloadsDir.canWrite()) return DownloadHelper.getOfflineStorageDir(this)
|
||||
return downloadsDir
|
||||
}
|
||||
|
@ -286,7 +286,9 @@ class MainActivity : BaseActivity() {
|
||||
searchViewModel.setQuery(null)
|
||||
navController.navigate(R.id.searchFragment)
|
||||
}
|
||||
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS or MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW)
|
||||
item.setShowAsAction(
|
||||
MenuItem.SHOW_AS_ACTION_ALWAYS or MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
@ -300,8 +302,8 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
// Handover back press to `BackPressedDispatcher`
|
||||
else if (binding.bottomNav.menu.children.none {
|
||||
it.itemId == navController.currentDestination?.id
|
||||
}
|
||||
it.itemId == navController.currentDestination?.id
|
||||
}
|
||||
) {
|
||||
this@MainActivity.onBackPressedDispatcher.onBackPressed()
|
||||
}
|
||||
|
@ -67,7 +67,10 @@ class CommentsAdapter(
|
||||
}
|
||||
|
||||
commentInfos.text = comment.author.toString() + TextUtils.SEPARATOR + comment.commentedTime.toString()
|
||||
commentText.text = HtmlCompat.fromHtml(comment.commentText.toString(), HtmlCompat.FROM_HTML_MODE_LEGACY)
|
||||
commentText.text = HtmlCompat.fromHtml(
|
||||
comment.commentText.toString(),
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
|
||||
ImageHelper.loadImage(comment.thumbnail, commentorImage)
|
||||
likesTextView.text = comment.likeCount.formatShort()
|
||||
@ -102,7 +105,11 @@ class CommentsAdapter(
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMoreReplies(nextPage: String, showMoreBtn: Button, repliesAdapter: CommentsAdapter) {
|
||||
private fun showMoreReplies(
|
||||
nextPage: String,
|
||||
showMoreBtn: Button,
|
||||
repliesAdapter: CommentsAdapter
|
||||
) {
|
||||
when (repliesAdapter.itemCount) {
|
||||
0 -> {
|
||||
fetchReplies(nextPage) {
|
||||
|
@ -61,8 +61,14 @@ class DownloadsAdapter(
|
||||
) { _, index ->
|
||||
when (index) {
|
||||
0 -> {
|
||||
val audioDir = DownloadHelper.getDownloadDir(root.context, DownloadHelper.AUDIO_DIR)
|
||||
val videoDir = DownloadHelper.getDownloadDir(root.context, DownloadHelper.VIDEO_DIR)
|
||||
val audioDir = DownloadHelper.getDownloadDir(
|
||||
root.context,
|
||||
DownloadHelper.AUDIO_DIR
|
||||
)
|
||||
val videoDir = DownloadHelper.getDownloadDir(
|
||||
root.context,
|
||||
DownloadHelper.VIDEO_DIR
|
||||
)
|
||||
|
||||
listOf(audioDir, videoDir).forEach {
|
||||
val f = File(it, file.name)
|
||||
|
@ -20,10 +20,10 @@ import com.github.libretube.ui.sheets.VideoOptionsBottomSheet
|
||||
import com.github.libretube.ui.viewholders.PlaylistViewHolder
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
|
||||
class PlaylistAdapter(
|
||||
private val videoFeed: MutableList<StreamItem>,
|
||||
|
@ -18,7 +18,11 @@ class PlaylistBookmarkAdapter(
|
||||
private val bookmarkMode: BookmarkMode = BookmarkMode.FRAGMENT
|
||||
) : RecyclerView.Adapter<PlaylistBookmarkViewHolder>() {
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PlaylistBookmarkViewHolder {
|
||||
val binding = PlaylistBookmarkRowBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
||||
val binding = PlaylistBookmarkRowBinding.inflate(
|
||||
LayoutInflater.from(parent.context),
|
||||
parent,
|
||||
false
|
||||
)
|
||||
return PlaylistBookmarkViewHolder(binding)
|
||||
}
|
||||
|
||||
@ -40,7 +44,11 @@ class PlaylistBookmarkAdapter(
|
||||
uploaderName.text = bookmark.uploader
|
||||
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigatePlaylist(root.context, bookmark.playlistId, PlaylistType.PUBLIC)
|
||||
NavigationHelper.navigatePlaylist(
|
||||
root.context,
|
||||
bookmark.playlistId,
|
||||
PlaylistType.PUBLIC
|
||||
)
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
|
@ -102,7 +102,10 @@ class SearchAdapter(
|
||||
val videoName = item.title!!
|
||||
root.setOnLongClickListener {
|
||||
VideoOptionsBottomSheet(videoId, videoName)
|
||||
.show((root.context as BaseActivity).supportFragmentManager, VideoOptionsBottomSheet::class.java.name)
|
||||
.show(
|
||||
(root.context as BaseActivity).supportFragmentManager,
|
||||
VideoOptionsBottomSheet::class.java.name
|
||||
)
|
||||
true
|
||||
}
|
||||
channelContainer.setOnClickListener {
|
||||
@ -123,7 +126,10 @@ class SearchAdapter(
|
||||
searchViews.text = root.context.getString(
|
||||
R.string.subscribers,
|
||||
item.subscribers.formatShort()
|
||||
) + TextUtils.SEPARATOR + root.context.getString(R.string.videoCount, item.videos.toString())
|
||||
) + TextUtils.SEPARATOR + root.context.getString(
|
||||
R.string.videoCount,
|
||||
item.videos.toString()
|
||||
)
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigateChannel(root.context, item.url)
|
||||
}
|
||||
@ -155,7 +161,10 @@ class SearchAdapter(
|
||||
val playlistId = item.url!!.toID()
|
||||
val playlistName = item.name!!
|
||||
PlaylistOptionsBottomSheet(playlistId, playlistName, PlaylistType.PUBLIC)
|
||||
.show((root.context as BaseActivity).supportFragmentManager, PlaylistOptionsBottomSheet::class.java.name)
|
||||
.show(
|
||||
(root.context as BaseActivity).supportFragmentManager,
|
||||
PlaylistOptionsBottomSheet::class.java.name
|
||||
)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -64,9 +64,15 @@ class VideosAdapter(
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VideosViewHolder {
|
||||
val layoutInflater = LayoutInflater.from(parent.context)
|
||||
return when {
|
||||
viewType == CAUGHT_UP_TYPE -> VideosViewHolder(AllCaughtUpRowBinding.inflate(layoutInflater, parent, false))
|
||||
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED, ForceMode.HOME) -> VideosViewHolder(TrendingRowBinding.inflate(layoutInflater, parent, false))
|
||||
forceMode == ForceMode.CHANNEL -> VideosViewHolder(VideoRowBinding.inflate(layoutInflater, parent, false))
|
||||
viewType == CAUGHT_UP_TYPE -> VideosViewHolder(
|
||||
AllCaughtUpRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
forceMode in listOf(ForceMode.TRENDING, ForceMode.RELATED, ForceMode.HOME) -> VideosViewHolder(
|
||||
TrendingRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
forceMode == ForceMode.CHANNEL -> VideosViewHolder(
|
||||
VideoRowBinding.inflate(layoutInflater, parent, false)
|
||||
)
|
||||
PreferenceHelper.getBoolean(
|
||||
PreferenceKeys.ALTERNATIVE_VIDEOS_LAYOUT,
|
||||
false
|
||||
@ -102,7 +108,9 @@ class VideosAdapter(
|
||||
video.uploaderName + TextUtils.SEPARATOR +
|
||||
video.views.formatShort() + " " +
|
||||
root.context.getString(R.string.views_placeholder) +
|
||||
TextUtils.SEPARATOR + video.uploaded?.let { DateUtils.getRelativeTimeSpanString(it) }
|
||||
TextUtils.SEPARATOR + video.uploaded?.let {
|
||||
DateUtils.getRelativeTimeSpanString(it)
|
||||
}
|
||||
video.duration?.let { thumbnailDuration.setFormattedDuration(it) }
|
||||
channelImage.setOnClickListener {
|
||||
NavigationHelper.navigateChannel(root.context, video.uploaderUrl)
|
||||
@ -118,7 +126,10 @@ class VideosAdapter(
|
||||
if (videoId == null || videoName == null) return@setOnLongClickListener true
|
||||
|
||||
VideoOptionsBottomSheet(videoId, videoName)
|
||||
.show((root.context as BaseActivity).supportFragmentManager, VideoOptionsBottomSheet::class.java.name)
|
||||
.show(
|
||||
(root.context as BaseActivity).supportFragmentManager,
|
||||
VideoOptionsBottomSheet::class.java.name
|
||||
)
|
||||
|
||||
true
|
||||
}
|
||||
@ -134,7 +145,9 @@ class VideosAdapter(
|
||||
videoInfo.text =
|
||||
video.views.formatShort() + " " +
|
||||
root.context.getString(R.string.views_placeholder) +
|
||||
TextUtils.SEPARATOR + video.uploaded?.let { DateUtils.getRelativeTimeSpanString(it) }
|
||||
TextUtils.SEPARATOR + video.uploaded?.let {
|
||||
DateUtils.getRelativeTimeSpanString(it)
|
||||
}
|
||||
|
||||
thumbnailDuration.text =
|
||||
video.duration?.let { DateUtils.formatElapsedTime(it) }
|
||||
@ -159,7 +172,10 @@ class VideosAdapter(
|
||||
root.setOnLongClickListener {
|
||||
if (videoId == null || videoName == null) return@setOnLongClickListener true
|
||||
VideoOptionsBottomSheet(videoId, videoName)
|
||||
.show((root.context as BaseActivity).supportFragmentManager, VideoOptionsBottomSheet::class.java.name)
|
||||
.show(
|
||||
(root.context as BaseActivity).supportFragmentManager,
|
||||
VideoOptionsBottomSheet::class.java.name
|
||||
)
|
||||
|
||||
true
|
||||
}
|
||||
|
@ -59,7 +59,10 @@ class WatchHistoryAdapter(
|
||||
}
|
||||
root.setOnLongClickListener {
|
||||
VideoOptionsBottomSheet(video.videoId, video.title!!)
|
||||
.show((root.context as BaseActivity).supportFragmentManager, VideoOptionsBottomSheet::class.java.name)
|
||||
.show(
|
||||
(root.context as BaseActivity).supportFragmentManager,
|
||||
VideoOptionsBottomSheet::class.java.name
|
||||
)
|
||||
true
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,10 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.databinding.DialogAddtoplaylistBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.toStreamItem
|
||||
import com.github.libretube.extensions.toastFromMainThread
|
||||
import com.github.libretube.ui.models.PlaylistViewModel
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
@ -86,7 +88,10 @@ class AddToPlaylistDialog(
|
||||
val appContext = context?.applicationContext ?: return
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val success = try {
|
||||
PlaylistsHelper.addToPlaylist(playlistId, videoId)
|
||||
PlaylistsHelper.addToPlaylist(
|
||||
playlistId,
|
||||
RetrofitInstance.api.getStreams(videoId).toStreamItem(videoId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
appContext.toastFromMainThread(R.string.unknown_error)
|
||||
|
@ -38,7 +38,9 @@ class DeletePlaylistDialog(
|
||||
if (playlistType == PlaylistType.LOCAL) {
|
||||
awaitQuery {
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistById(playlistId)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(playlistId)
|
||||
DatabaseHolder.Database.localPlaylistsDao().deletePlaylistItemsByPlaylistId(
|
||||
playlistId
|
||||
)
|
||||
}
|
||||
onSuccess.invoke()
|
||||
return
|
||||
|
@ -21,8 +21,8 @@ import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.MetadataHelper
|
||||
import com.github.libretube.util.ThemeHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
||||
class DownloadDialog(
|
||||
private val videoId: String
|
||||
|
@ -20,7 +20,10 @@ class NavBarOptionsDialog : DialogFragment() {
|
||||
|
||||
val options = NavBarHelper.getNavBarItems(requireContext())
|
||||
|
||||
val adapter = NavBarOptionsAdapter(options.toMutableList(), NavBarHelper.getStartFragmentId(requireContext()))
|
||||
val adapter = NavBarOptionsAdapter(
|
||||
options.toMutableList(),
|
||||
NavBarHelper.getStartFragmentId(requireContext())
|
||||
)
|
||||
|
||||
val itemTouchCallback = object : ItemTouchHelper.Callback() {
|
||||
override fun getMovementFlags(
|
||||
|
@ -27,11 +27,11 @@ import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.ui.dialogs.ShareDialog
|
||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import java.io.IOException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
|
||||
class ChannelFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentChannelBinding
|
||||
@ -134,7 +134,11 @@ class ChannelFragment : BaseFragment() {
|
||||
if (isSubscribed == null) return@launchWhenCreated
|
||||
|
||||
runOnUiThread {
|
||||
binding.channelSubscribe.setupSubscriptionButton(channelId, channelName, binding.notificationBell)
|
||||
binding.channelSubscribe.setupSubscriptionButton(
|
||||
channelId,
|
||||
channelName,
|
||||
binding.notificationBell
|
||||
)
|
||||
|
||||
binding.channelShare.setOnClickListener {
|
||||
val shareDialog = ShareDialog(
|
||||
|
@ -79,7 +79,11 @@ class HomeFragment : BaseFragment() {
|
||||
if (feed.isEmpty()) return@runOrError
|
||||
runOnUiThread {
|
||||
makeVisible(binding.featuredRV, binding.featuredTV)
|
||||
binding.featuredRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.featuredRV.layoutManager = LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
binding.featuredRV.adapter = VideosAdapter(
|
||||
feed.toMutableList(),
|
||||
forceMode = VideosAdapter.Companion.ForceMode.HOME
|
||||
@ -108,17 +112,20 @@ class HomeFragment : BaseFragment() {
|
||||
runOnUiThread {
|
||||
makeVisible(binding.playlistsRV, binding.playlistsTV)
|
||||
binding.playlistsRV.layoutManager = LinearLayoutManager(context)
|
||||
binding.playlistsRV.adapter = PlaylistsAdapter(playlists.toMutableList(), PlaylistsHelper.getPrivatePlaylistType())
|
||||
binding.playlistsRV.adapter = PlaylistsAdapter(
|
||||
playlists.toMutableList(),
|
||||
PlaylistsHelper.getPrivatePlaylistType()
|
||||
)
|
||||
binding.playlistsRV.adapter?.registerAdapterDataObserver(object :
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
if (itemCount == 0) {
|
||||
binding.playlistsRV.visibility = View.GONE
|
||||
binding.playlistsTV.visibility = View.GONE
|
||||
}
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
if (itemCount == 0) {
|
||||
binding.playlistsRV.visibility = View.GONE
|
||||
binding.playlistsTV.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -129,7 +136,11 @@ class HomeFragment : BaseFragment() {
|
||||
if (bookmarkedPlaylists.isEmpty()) return@runOrError
|
||||
runOnUiThread {
|
||||
makeVisible(binding.bookmarksTV, binding.bookmarksRV)
|
||||
binding.bookmarksRV.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||
binding.bookmarksRV.layoutManager = LinearLayoutManager(
|
||||
context,
|
||||
LinearLayoutManager.HORIZONTAL,
|
||||
false
|
||||
)
|
||||
binding.bookmarksRV.adapter = PlaylistBookmarkAdapter(
|
||||
bookmarkedPlaylists,
|
||||
PlaylistBookmarkAdapter.Companion.BookmarkMode.HOME
|
||||
|
@ -128,13 +128,13 @@ class LibraryFragment : BaseFragment() {
|
||||
|
||||
// listen for playlists to become deleted
|
||||
playlistsAdapter.registerAdapterDataObserver(object :
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
binding.nothingHere.visibility =
|
||||
if (playlistsAdapter.itemCount == 0) View.VISIBLE else View.GONE
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
}
|
||||
})
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
binding.nothingHere.visibility =
|
||||
if (playlistsAdapter.itemCount == 0) View.VISIBLE else View.GONE
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
}
|
||||
})
|
||||
|
||||
binding.nothingHere.visibility = View.GONE
|
||||
binding.playlistRecView.adapter = playlistsAdapter
|
||||
|
@ -105,15 +105,15 @@ import com.google.android.exoplayer2.ui.StyledPlayerView
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSource
|
||||
import com.google.android.exoplayer2.util.MimeTypes
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.abs
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.chromium.net.CronetEngine
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.abs
|
||||
|
||||
class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
@ -1136,8 +1136,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
for (vid in videoStreams) {
|
||||
if (resolutions.any {
|
||||
it.resolution == vid.quality.qualityToInt()
|
||||
} || vid.url == null
|
||||
it.resolution == vid.quality.qualityToInt()
|
||||
} || vid.url == null
|
||||
) {
|
||||
continue
|
||||
}
|
||||
@ -1160,7 +1160,11 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
if (resolutions.isEmpty()) {
|
||||
return listOf(
|
||||
VideoResolution(getString(R.string.hls), resolution = Int.MAX_VALUE, adaptiveSourceUrl = streams.hls)
|
||||
VideoResolution(
|
||||
getString(R.string.hls),
|
||||
resolution = Int.MAX_VALUE,
|
||||
adaptiveSourceUrl = streams.hls
|
||||
)
|
||||
)
|
||||
} else {
|
||||
resolutions.add(0, VideoResolution(getString(R.string.auto_quality), Int.MAX_VALUE))
|
||||
@ -1187,7 +1191,10 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
// set the default subtitle if available
|
||||
val newParams = trackSelector.buildUponParameters()
|
||||
if (PlayerHelper.defaultSubtitleCode != "" && subtitleCodesList.contains(PlayerHelper.defaultSubtitleCode)) {
|
||||
if (PlayerHelper.defaultSubtitleCode != "" && subtitleCodesList.contains(
|
||||
PlayerHelper.defaultSubtitleCode
|
||||
)
|
||||
) {
|
||||
newParams
|
||||
.setPreferredTextLanguage(PlayerHelper.defaultSubtitleCode)
|
||||
.setPreferredTextRoleFlags(C.ROLE_FLAG_CAPTION)
|
||||
@ -1464,7 +1471,10 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
return false
|
||||
}
|
||||
|
||||
val backgroundModeRunning = BackgroundHelper.isServiceRunning(requireContext(), BackgroundMode::class.java)
|
||||
val backgroundModeRunning = BackgroundHelper.isServiceRunning(
|
||||
requireContext(),
|
||||
BackgroundMode::class.java
|
||||
)
|
||||
|
||||
return exoPlayer.isPlaying && !backgroundModeRunning
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ import com.github.libretube.ui.sheets.PlaylistOptionsBottomSheet
|
||||
import com.github.libretube.util.ImageHelper
|
||||
import com.github.libretube.util.NavigationHelper
|
||||
import com.github.libretube.util.TextUtils
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
||||
class PlaylistFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentPlaylistBinding
|
||||
@ -175,29 +175,29 @@ class PlaylistFragment : BaseFragment() {
|
||||
|
||||
// listen for playlist items to become deleted
|
||||
playlistAdapter!!.registerAdapterDataObserver(object :
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
if (positionStart == 0) {
|
||||
ImageHelper.loadImage(
|
||||
playlistFeed.firstOrNull()?.thumbnail ?: "",
|
||||
binding.thumbnail
|
||||
)
|
||||
}
|
||||
|
||||
val info = binding.playlistInfo.text.split(TextUtils.SEPARATOR)
|
||||
binding.playlistInfo.text = (
|
||||
if (info.size == 2) {
|
||||
info[0] + TextUtils.SEPARATOR
|
||||
} else {
|
||||
""
|
||||
}
|
||||
) + getString(
|
||||
R.string.videoCount,
|
||||
playlistAdapter!!.itemCount.toString()
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
if (positionStart == 0) {
|
||||
ImageHelper.loadImage(
|
||||
playlistFeed.firstOrNull()?.thumbnail ?: "",
|
||||
binding.thumbnail
|
||||
)
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
}
|
||||
})
|
||||
|
||||
val info = binding.playlistInfo.text.split(TextUtils.SEPARATOR)
|
||||
binding.playlistInfo.text = (
|
||||
if (info.size == 2) {
|
||||
info[0] + TextUtils.SEPARATOR
|
||||
} else {
|
||||
""
|
||||
}
|
||||
) + getString(
|
||||
R.string.videoCount,
|
||||
playlistAdapter!!.itemCount.toString()
|
||||
)
|
||||
super.onItemRangeRemoved(positionStart, itemCount)
|
||||
}
|
||||
})
|
||||
|
||||
binding.playlistRecView.adapter = playlistAdapter
|
||||
binding.playlistScrollview.viewTreeObserver
|
||||
|
@ -18,8 +18,8 @@ import com.github.libretube.extensions.hideKeyboard
|
||||
import com.github.libretube.ui.adapters.SearchAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
||||
class SearchResultFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentSearchResultBinding
|
||||
|
@ -150,7 +150,9 @@ class SubscriptionsFragment : BaseFragment() {
|
||||
// add an "all caught up item"
|
||||
if (sortOrder == 0) {
|
||||
val lastCheckedFeedTime = PreferenceHelper.getLastCheckedFeedTime()
|
||||
val caughtUpIndex = feed.indexOfFirst { (it.uploaded ?: 0L) / 1000 < lastCheckedFeedTime }
|
||||
val caughtUpIndex = feed.indexOfFirst {
|
||||
(it.uploaded ?: 0L) / 1000 < lastCheckedFeedTime
|
||||
}
|
||||
if (caughtUpIndex > 0) {
|
||||
sortedFeed.add(caughtUpIndex, StreamItem(type = "caught"))
|
||||
}
|
||||
|
@ -17,8 +17,8 @@ import com.github.libretube.ui.adapters.VideosAdapter
|
||||
import com.github.libretube.ui.base.BaseFragment
|
||||
import com.github.libretube.util.LocaleHelper
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import retrofit2.HttpException
|
||||
import java.io.IOException
|
||||
import retrofit2.HttpException
|
||||
|
||||
class TrendsFragment : BaseFragment() {
|
||||
private lateinit var binding: FragmentTrendsBinding
|
||||
|
@ -88,14 +88,14 @@ class WatchHistoryFragment : BaseFragment() {
|
||||
|
||||
// observe changes
|
||||
watchHistoryAdapter.registerAdapterDataObserver(object :
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
if (watchHistoryAdapter.itemCount == 0) {
|
||||
binding.watchHistoryRecView.visibility = View.GONE
|
||||
binding.historyEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
|
||||
if (watchHistoryAdapter.itemCount == 0) {
|
||||
binding.watchHistoryRecView.visibility = View.GONE
|
||||
binding.historyEmpty.visibility = View.VISIBLE
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
binding.watchHistoryRecView.adapter = watchHistoryAdapter
|
||||
binding.historyEmpty.visibility = View.GONE
|
||||
|
@ -42,7 +42,10 @@ class AppearanceSettings : BasePreferenceFragment() {
|
||||
}
|
||||
|
||||
val changeIcon = findPreference<Preference>(PreferenceKeys.APP_ICON)
|
||||
val iconPref = PreferenceHelper.getString(PreferenceKeys.APP_ICON, IconsSheetAdapter.Companion.AppIcon.Default.activityAlias)
|
||||
val iconPref = PreferenceHelper.getString(
|
||||
PreferenceKeys.APP_ICON,
|
||||
IconsSheetAdapter.Companion.AppIcon.Default.activityAlias
|
||||
)
|
||||
IconsSheetAdapter.availableIcons.firstOrNull { it.activityAlias == iconPref }?.let {
|
||||
changeIcon?.summary = getString(it.nameResource)
|
||||
}
|
||||
|
@ -85,7 +85,11 @@ class MainSettings : BasePreferenceFragment() {
|
||||
// checking for update: yes -> dialog, no -> snackBar
|
||||
update?.setOnPreferenceClickListener {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Toast.makeText(context, "Updater is disabled for debug versions!", Toast.LENGTH_SHORT).show()
|
||||
Toast.makeText(
|
||||
context,
|
||||
"Updater is disabled for debug versions!",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
|
@ -40,9 +40,15 @@ class NotificationSettings : BasePreferenceFragment() {
|
||||
true
|
||||
}
|
||||
|
||||
val notificationTime = findPreference<SwitchPreferenceCompat>(PreferenceKeys.NOTIFICATION_TIME_ENABLED)
|
||||
val notificationStartTime = findPreference<TimePickerPreference>(PreferenceKeys.NOTIFICATION_START_TIME)
|
||||
val notificationEndTime = findPreference<TimePickerPreference>(PreferenceKeys.NOTIFICATION_END_TIME)
|
||||
val notificationTime = findPreference<SwitchPreferenceCompat>(
|
||||
PreferenceKeys.NOTIFICATION_TIME_ENABLED
|
||||
)
|
||||
val notificationStartTime = findPreference<TimePickerPreference>(
|
||||
PreferenceKeys.NOTIFICATION_START_TIME
|
||||
)
|
||||
val notificationEndTime = findPreference<TimePickerPreference>(
|
||||
PreferenceKeys.NOTIFICATION_END_TIME
|
||||
)
|
||||
listOf(notificationStartTime, notificationEndTime).forEach {
|
||||
it?.isEnabled = notificationTime?.isChecked == true
|
||||
}
|
||||
|
@ -28,7 +28,11 @@ class CommentsSheet(
|
||||
private lateinit var commentsAdapter: CommentsAdapter
|
||||
private var isLoading = false
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
binding = CommentsSheetBinding.inflate(layoutInflater)
|
||||
// set a fixed maximum height
|
||||
binding.root.maxHeight = maxHeight
|
||||
|
@ -244,8 +244,12 @@ internal class CustomExoPlayerView(
|
||||
R.drawable.ic_aspect_ratio,
|
||||
{
|
||||
when (resizeMode) {
|
||||
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(R.string.resize_mode_fit)
|
||||
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(R.string.resize_mode_fill)
|
||||
AspectRatioFrameLayout.RESIZE_MODE_FIT -> context.getString(
|
||||
R.string.resize_mode_fit
|
||||
)
|
||||
AspectRatioFrameLayout.RESIZE_MODE_FILL -> context.getString(
|
||||
R.string.resize_mode_fill
|
||||
)
|
||||
else -> context.getString(R.string.resize_mode_zoom)
|
||||
}
|
||||
}
|
||||
@ -257,9 +261,9 @@ internal class CustomExoPlayerView(
|
||||
R.drawable.ic_speed,
|
||||
{
|
||||
"${
|
||||
player?.playbackParameters?.speed
|
||||
.toString()
|
||||
.replace(".0", "")
|
||||
player?.playbackParameters?.speed
|
||||
.toString()
|
||||
.replace(".0", "")
|
||||
}x"
|
||||
}
|
||||
) {
|
||||
@ -403,7 +407,9 @@ internal class CustomExoPlayerView(
|
||||
// If brightness progress goes to below 0, set to system brightness
|
||||
if (distance <= 0) {
|
||||
brightnessHelper.resetToSystemBrightness()
|
||||
gestureViewBinding.brightnessImageView.setImageResource(R.drawable.ic_brightness_auto)
|
||||
gestureViewBinding.brightnessImageView.setImageResource(
|
||||
R.drawable.ic_brightness_auto
|
||||
)
|
||||
gestureViewBinding.brightnessTextView.text = resources.getString(R.string.auto)
|
||||
return
|
||||
}
|
||||
|
@ -35,7 +35,10 @@ class SliderPreference(
|
||||
)
|
||||
}
|
||||
|
||||
private val typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.SliderPreference)
|
||||
private val typedArray = context.obtainStyledAttributes(
|
||||
attributeSet,
|
||||
R.styleable.SliderPreference
|
||||
)
|
||||
|
||||
override fun onAttached() {
|
||||
super.onAttached()
|
||||
|
@ -52,7 +52,12 @@ class BrightnessHelper(private val activity: Activity) {
|
||||
* Set current brightness value with scaling to given range.
|
||||
* [shouldSave] determines whether the value should be persisted.
|
||||
*/
|
||||
fun setBrightnessWithScale(value: Float, maxValue: Float, minValue: Float = 0.0f, shouldSave: Boolean = false) {
|
||||
fun setBrightnessWithScale(
|
||||
value: Float,
|
||||
maxValue: Float,
|
||||
minValue: Float = 0.0f,
|
||||
shouldSave: Boolean = false
|
||||
) {
|
||||
brightness = value.normalize(minValue, maxValue, minBrightness, maxBrightness)
|
||||
if (shouldSave) savedBrightness = brightness
|
||||
}
|
||||
|
@ -2,14 +2,14 @@ package com.github.libretube.util
|
||||
|
||||
import com.github.libretube.api.obj.PipedStream
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
import java.io.StringWriter
|
||||
import javax.xml.parsers.DocumentBuilder
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
import javax.xml.transform.TransformerFactory
|
||||
import javax.xml.transform.dom.DOMSource
|
||||
import javax.xml.transform.stream.StreamResult
|
||||
import org.w3c.dom.Document
|
||||
import org.w3c.dom.Element
|
||||
|
||||
// Based off of https://github.com/TeamPiped/Piped/blob/master/src/utils/DashUtils.js
|
||||
|
||||
@ -66,7 +66,9 @@ object DashHelper {
|
||||
|
||||
for (stream in streams.audioStreams!!) {
|
||||
val adapSetInfo =
|
||||
adapSetInfos.find { it.mimeType == stream.mimeType && it.audioTrackId == stream.audioTrackId }
|
||||
adapSetInfos.find {
|
||||
it.mimeType == stream.mimeType && it.audioTrackId == stream.audioTrackId
|
||||
}
|
||||
if (adapSetInfo != null) {
|
||||
adapSetInfo.formats.add(stream)
|
||||
continue
|
||||
|
@ -13,9 +13,9 @@ import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import com.github.libretube.api.CronetHelper
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import okio.use
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import okio.use
|
||||
|
||||
object ImageHelper {
|
||||
lateinit var imageLoader: ImageLoader
|
||||
|
@ -15,11 +15,11 @@ import com.github.libretube.obj.ImportPlaylist
|
||||
import com.github.libretube.obj.ImportPlaylistFile
|
||||
import com.github.libretube.obj.NewPipeSubscription
|
||||
import com.github.libretube.obj.NewPipeSubscriptions
|
||||
import java.io.FileOutputStream
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class ImportHelper(
|
||||
private val activity: Activity
|
||||
@ -56,7 +56,10 @@ class ImportHelper(
|
||||
return when (val fileType = activity.contentResolver.getType(uri)) {
|
||||
"application/json", "application/*", "application/octet-stream" -> {
|
||||
// NewPipe subscriptions format
|
||||
val subscriptions = ObjectMapper().readValue(uri.readText(), NewPipeSubscriptions::class.java)
|
||||
val subscriptions = ObjectMapper().readValue(
|
||||
uri.readText(),
|
||||
NewPipeSubscriptions::class.java
|
||||
)
|
||||
subscriptions.subscriptions.orEmpty().map {
|
||||
it.url!!.replace("https://www.youtube.com/channel/", "")
|
||||
}
|
||||
@ -131,7 +134,10 @@ class ImportHelper(
|
||||
}
|
||||
}
|
||||
"application/json", "application/*", "application/octet-stream" -> {
|
||||
val playlistFile = ObjectMapper().readValue(uri.readText(), ImportPlaylistFile::class.java)
|
||||
val playlistFile = ObjectMapper().readValue(
|
||||
uri.readText(),
|
||||
ImportPlaylistFile::class.java
|
||||
)
|
||||
importPlaylists.addAll(playlistFile.playlists.orEmpty())
|
||||
}
|
||||
else -> {
|
||||
|
@ -124,7 +124,13 @@ object PreferenceHelper {
|
||||
|
||||
fun toggleIgnorableNotificationChannel(channelId: String) {
|
||||
val ignorableChannels = getIgnorableNotificationChannels().toMutableList()
|
||||
if (ignorableChannels.contains(channelId)) ignorableChannels.remove(channelId) else ignorableChannels.add(channelId)
|
||||
if (ignorableChannels.contains(channelId)) {
|
||||
ignorableChannels.remove(channelId)
|
||||
} else {
|
||||
ignorableChannels.add(
|
||||
channelId
|
||||
)
|
||||
}
|
||||
editor.putString(
|
||||
PreferenceKeys.IGNORED_NOTIFICATION_CHANNELS,
|
||||
ignorableChannels.joinToString(",")
|
||||
|
@ -2,13 +2,13 @@ package com.github.libretube.util
|
||||
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.URI
|
||||
import java.net.URLDecoder
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.util.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
object ProxyHelper {
|
||||
private fun getImageProxyUrl(): String? {
|
||||
|
@ -17,8 +17,8 @@ import com.github.libretube.extensions.toID
|
||||
import com.github.libretube.ui.activities.MainActivity
|
||||
import com.github.libretube.ui.views.TimePickerPreference
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.time.LocalTime
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
/**
|
||||
* The notification worker which checks for new streams in a certain frequency
|
||||
|
Loading…
Reference in New Issue
Block a user