mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-28 16:00:31 +05:30
feat: support for DeArrow
This commit is contained in:
parent
5bb076c94f
commit
04b9a3a4c9
@ -18,6 +18,7 @@ import com.github.libretube.api.obj.Subscribe
|
|||||||
import com.github.libretube.api.obj.Subscribed
|
import com.github.libretube.api.obj.Subscribed
|
||||||
import com.github.libretube.api.obj.Subscription
|
import com.github.libretube.api.obj.Subscription
|
||||||
import com.github.libretube.api.obj.Token
|
import com.github.libretube.api.obj.Token
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Header
|
import retrofit2.http.Header
|
||||||
@ -45,6 +46,11 @@ interface PipedApi {
|
|||||||
@Query("category") category: String
|
@Query("category") category: String
|
||||||
): SegmentData
|
): SegmentData
|
||||||
|
|
||||||
|
@GET("dearrow")
|
||||||
|
suspend fun getDeArrowContent(
|
||||||
|
@Query("videoIds") videoIds: String
|
||||||
|
): JsonObject
|
||||||
|
|
||||||
@GET("nextpage/comments/{videoId}")
|
@GET("nextpage/comments/{videoId}")
|
||||||
suspend fun getCommentsNextPage(
|
suspend fun getCommentsNextPage(
|
||||||
@Path("videoId") videoId: String,
|
@Path("videoId") videoId: String,
|
||||||
|
@ -16,6 +16,7 @@ import com.github.libretube.helpers.ProxyHelper
|
|||||||
import com.github.libretube.obj.FreeTubeImportPlaylist
|
import com.github.libretube.obj.FreeTubeImportPlaylist
|
||||||
import com.github.libretube.obj.FreeTubeVideo
|
import com.github.libretube.obj.FreeTubeVideo
|
||||||
import com.github.libretube.obj.PipedImportPlaylist
|
import com.github.libretube.obj.PipedImportPlaylist
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@ -26,9 +27,7 @@ object PlaylistsHelper {
|
|||||||
"[\\da-fA-F]{8}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{12}".toRegex()
|
"[\\da-fA-F]{8}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{4}-[\\da-fA-F]{12}".toRegex()
|
||||||
|
|
||||||
private val token get() = PreferenceHelper.getToken()
|
private val token get() = PreferenceHelper.getToken()
|
||||||
|
|
||||||
val loggedIn: Boolean get() = token.isNotEmpty()
|
val loggedIn: Boolean get() = token.isNotEmpty()
|
||||||
|
|
||||||
private fun Message.isOk() = this.message == "ok"
|
private fun Message.isOk() = this.message == "ok"
|
||||||
|
|
||||||
suspend fun getPlaylists(): List<Playlists> = withContext(Dispatchers.IO) {
|
suspend fun getPlaylists(): List<Playlists> = withContext(Dispatchers.IO) {
|
||||||
@ -64,6 +63,8 @@ object PlaylistsHelper {
|
|||||||
relatedStreams = relation.videos.map { it.toStreamItem() }
|
relatedStreams = relation.videos.map { it.toStreamItem() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}.apply {
|
||||||
|
relatedStreams = relatedStreams.deArrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import com.github.libretube.db.DatabaseHolder.Database
|
|||||||
import com.github.libretube.db.obj.LocalSubscription
|
import com.github.libretube.db.obj.LocalSubscription
|
||||||
import com.github.libretube.extensions.TAG
|
import com.github.libretube.extensions.TAG
|
||||||
import com.github.libretube.helpers.PreferenceHelper
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
@ -137,6 +138,6 @@ object SubscriptionHelper {
|
|||||||
subscriptions.joinToString(",")
|
subscriptions.joinToString(",")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}.deArrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ data class Channel(
|
|||||||
val nextpage: String? = null,
|
val nextpage: String? = null,
|
||||||
val subscriberCount: Long = 0,
|
val subscriberCount: Long = 0,
|
||||||
val verified: Boolean = false,
|
val verified: Boolean = false,
|
||||||
val relatedStreams: List<StreamItem> = emptyList(),
|
var relatedStreams: List<StreamItem> = emptyList(),
|
||||||
val tabs: List<ChannelTab> = emptyList()
|
val tabs: List<ChannelTab> = emptyList()
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,6 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ChannelTabResponse(
|
data class ChannelTabResponse(
|
||||||
val content: List<ContentItem> = emptyList(),
|
var content: List<ContentItem> = emptyList(),
|
||||||
val nextpage: String? = null
|
val nextpage: String? = null
|
||||||
)
|
)
|
||||||
|
@ -6,9 +6,9 @@ import kotlinx.serialization.Serializable
|
|||||||
data class ContentItem(
|
data class ContentItem(
|
||||||
val url: String,
|
val url: String,
|
||||||
val type: String,
|
val type: String,
|
||||||
val thumbnail: String,
|
var thumbnail: String,
|
||||||
// Video only attributes
|
// Video only attributes
|
||||||
val title: String? = null,
|
var title: String? = null,
|
||||||
val uploaderUrl: String? = null,
|
val uploaderUrl: String? = null,
|
||||||
val uploaderAvatar: String? = null,
|
val uploaderAvatar: String? = null,
|
||||||
val duration: Long = -1,
|
val duration: Long = -1,
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.github.libretube.api.obj
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DeArrowContent(
|
||||||
|
val thumbnails: List<DeArrowThumbnail>,
|
||||||
|
val titles: List<DeArrowTitle>,
|
||||||
|
val randomTime: Float?,
|
||||||
|
val videoDuration: Float?
|
||||||
|
)
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.github.libretube.api.obj
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DeArrowThumbnail(
|
||||||
|
val UUID: String,
|
||||||
|
val locked: Boolean,
|
||||||
|
val original: Boolean,
|
||||||
|
val thumbnail: String? = null,
|
||||||
|
val timestamp: Float?,
|
||||||
|
val votes: Int
|
||||||
|
)
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.github.libretube.api.obj
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class DeArrowTitle(
|
||||||
|
val UUID: String,
|
||||||
|
val locked: Boolean,
|
||||||
|
val original: Boolean,
|
||||||
|
val title: String,
|
||||||
|
val votes: Int
|
||||||
|
)
|
@ -14,7 +14,7 @@ data class Playlist(
|
|||||||
val uploaderUrl: String? = null,
|
val uploaderUrl: String? = null,
|
||||||
val uploaderAvatar: String? = null,
|
val uploaderAvatar: String? = null,
|
||||||
val videos: Int = 0,
|
val videos: Int = 0,
|
||||||
val relatedStreams: List<StreamItem> = emptyList()
|
var relatedStreams: List<StreamItem> = emptyList()
|
||||||
) {
|
) {
|
||||||
fun toPlaylistBookmark(playlistId: String): PlaylistBookmark {
|
fun toPlaylistBookmark(playlistId: String): PlaylistBookmark {
|
||||||
return PlaylistBookmark(
|
return PlaylistBookmark(
|
||||||
|
@ -4,7 +4,7 @@ import kotlinx.serialization.Serializable
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SearchResult(
|
data class SearchResult(
|
||||||
val items: List<ContentItem> = emptyList(),
|
var items: List<ContentItem> = emptyList(),
|
||||||
val nextpage: String? = null,
|
val nextpage: String? = null,
|
||||||
val suggestion: String? = null,
|
val suggestion: String? = null,
|
||||||
val corrected: Boolean? = null
|
val corrected: Boolean? = null
|
||||||
|
@ -8,8 +8,8 @@ import kotlinx.serialization.Serializable
|
|||||||
data class StreamItem(
|
data class StreamItem(
|
||||||
val url: String? = null,
|
val url: String? = null,
|
||||||
val type: String? = null,
|
val type: String? = null,
|
||||||
val title: String? = null,
|
var title: String? = null,
|
||||||
val thumbnail: String? = null,
|
var thumbnail: String? = null,
|
||||||
val uploaderName: String? = null,
|
val uploaderName: String? = null,
|
||||||
val uploaderUrl: String? = null,
|
val uploaderUrl: String? = null,
|
||||||
val uploaderAvatar: String? = null,
|
val uploaderAvatar: String? = null,
|
||||||
|
@ -28,7 +28,7 @@ data class Streams(
|
|||||||
val dislikes: Long = 0,
|
val dislikes: Long = 0,
|
||||||
val audioStreams: List<PipedStream> = emptyList(),
|
val audioStreams: List<PipedStream> = emptyList(),
|
||||||
val videoStreams: List<PipedStream> = emptyList(),
|
val videoStreams: List<PipedStream> = emptyList(),
|
||||||
val relatedStreams: List<StreamItem> = emptyList(),
|
var relatedStreams: List<StreamItem> = emptyList(),
|
||||||
val subtitles: List<Subtitle> = emptyList(),
|
val subtitles: List<Subtitle> = emptyList(),
|
||||||
val livestream: Boolean = false,
|
val livestream: Boolean = false,
|
||||||
val proxyUrl: String? = null,
|
val proxyUrl: String? = null,
|
||||||
|
@ -82,6 +82,7 @@ object PreferenceKeys {
|
|||||||
const val PICTURE_IN_PICTURE = "picture_in_picture"
|
const val PICTURE_IN_PICTURE = "picture_in_picture"
|
||||||
const val PLAYER_RESIZE_MODE = "player_resize_mode"
|
const val PLAYER_RESIZE_MODE = "player_resize_mode"
|
||||||
const val SB_SHOW_MARKERS = "sb_show_markers"
|
const val SB_SHOW_MARKERS = "sb_show_markers"
|
||||||
|
const val DEARROW = "dearrow"
|
||||||
const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout"
|
const val ALTERNATIVE_PLAYER_LAYOUT = "alternative_player_layout"
|
||||||
const val USE_HLS_OVER_DASH = "use_hls"
|
const val USE_HLS_OVER_DASH = "use_hls"
|
||||||
const val QUEUE_AUTO_INSERT_RELATED = "queue_insert_related_videos"
|
const val QUEUE_AUTO_INSERT_RELATED = "queue_insert_related_videos"
|
||||||
|
@ -29,6 +29,7 @@ import com.github.libretube.ui.adapters.SearchAdapter
|
|||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
import com.github.libretube.ui.dialogs.ShareDialog
|
import com.github.libretube.ui.dialogs.ShareDialog
|
||||||
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
import com.github.libretube.ui.extensions.setupSubscriptionButton
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -115,6 +116,8 @@ class ChannelFragment : Fragment() {
|
|||||||
RetrofitInstance.api.getChannel(channelId!!)
|
RetrofitInstance.api.getChannel(channelId!!)
|
||||||
} else {
|
} else {
|
||||||
RetrofitInstance.api.getChannelByName(channelName!!)
|
RetrofitInstance.api.getChannelByName(channelName!!)
|
||||||
|
}.apply {
|
||||||
|
relatedStreams = relatedStreams.deArrow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
@ -240,6 +243,8 @@ class ChannelFragment : Fragment() {
|
|||||||
val response = try {
|
val response = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getChannelTab(tab.data)
|
RetrofitInstance.api.getChannelTab(tab.data)
|
||||||
|
}.apply {
|
||||||
|
content = content.deArrow()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
return@launch
|
return@launch
|
||||||
@ -270,7 +275,9 @@ class ChannelFragment : Fragment() {
|
|||||||
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
repeatOnLifecycle(Lifecycle.State.CREATED) {
|
||||||
val response = try {
|
val response = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!)
|
RetrofitInstance.api.getChannelNextPage(channelId!!, nextPage!!).apply {
|
||||||
|
relatedStreams = relatedStreams.deArrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
_binding?.channelRefresh?.isRefreshing = false
|
_binding?.channelRefresh?.isRefreshing = false
|
||||||
@ -301,6 +308,8 @@ class ChannelFragment : Fragment() {
|
|||||||
val newContent = try {
|
val newContent = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getChannelTab(tab.data, nextPage)
|
RetrofitInstance.api.getChannelTab(tab.data, nextPage)
|
||||||
|
}.apply {
|
||||||
|
content = content.deArrow()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG(), "Exception: $e")
|
Log.e(TAG(), "Exception: $e")
|
||||||
|
@ -30,6 +30,7 @@ import com.github.libretube.ui.adapters.PlaylistBookmarkAdapter
|
|||||||
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
import com.github.libretube.ui.adapters.PlaylistsAdapter
|
||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
import com.github.libretube.ui.models.SubscriptionsViewModel
|
import com.github.libretube.ui.models.SubscriptionsViewModel
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.awaitAll
|
import kotlinx.coroutines.awaitAll
|
||||||
@ -116,7 +117,7 @@ class HomeFragment : Fragment() {
|
|||||||
val region = LocaleHelper.getTrendingRegion(requireContext())
|
val region = LocaleHelper.getTrendingRegion(requireContext())
|
||||||
val trending = runCatching {
|
val trending = runCatching {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
RetrofitInstance.api.getTrending(region).take(10)
|
RetrofitInstance.api.getTrending(region).deArrow().take(10)
|
||||||
}
|
}
|
||||||
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
|
}.getOrNull()?.takeIf { it.isNotEmpty() } ?: return
|
||||||
val binding = _binding ?: return
|
val binding = _binding ?: return
|
||||||
|
@ -114,6 +114,7 @@ import com.github.libretube.util.PlayingQueue
|
|||||||
import com.github.libretube.util.TextUtils
|
import com.github.libretube.util.TextUtils
|
||||||
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
import com.github.libretube.util.TextUtils.toTimeInSeconds
|
||||||
import com.github.libretube.util.YoutubeHlsPlaylistParser
|
import com.github.libretube.util.YoutubeHlsPlaylistParser
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -690,7 +691,9 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
|||||||
|
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
streams = try {
|
streams = try {
|
||||||
RetrofitInstance.api.getStreams(videoId)
|
RetrofitInstance.api.getStreams(videoId).apply {
|
||||||
|
relatedStreams = relatedStreams.deArrow()
|
||||||
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
context?.toastFromMainDispatcher(R.string.unknown_error, Toast.LENGTH_LONG)
|
context?.toastFromMainDispatcher(R.string.unknown_error, Toast.LENGTH_LONG)
|
||||||
return@launch
|
return@launch
|
||||||
|
@ -21,6 +21,7 @@ import com.github.libretube.extensions.TAG
|
|||||||
import com.github.libretube.extensions.hideKeyboard
|
import com.github.libretube.extensions.hideKeyboard
|
||||||
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.util.deArrow
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -94,7 +95,9 @@ class SearchResultFragment : Fragment() {
|
|||||||
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)
|
RetrofitInstance.api.getSearchResults(query, apiSearchFilter).apply {
|
||||||
|
items = items.deArrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
@ -124,7 +127,9 @@ class SearchResultFragment : Fragment() {
|
|||||||
query,
|
query,
|
||||||
apiSearchFilter,
|
apiSearchFilter,
|
||||||
nextPage!!
|
nextPage!!
|
||||||
)
|
).apply {
|
||||||
|
items = items.deArrow()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
|
@ -18,6 +18,7 @@ import com.github.libretube.extensions.TAG
|
|||||||
import com.github.libretube.helpers.LocaleHelper
|
import com.github.libretube.helpers.LocaleHelper
|
||||||
import com.github.libretube.ui.activities.SettingsActivity
|
import com.github.libretube.ui.activities.SettingsActivity
|
||||||
import com.github.libretube.ui.adapters.VideosAdapter
|
import com.github.libretube.ui.adapters.VideosAdapter
|
||||||
|
import com.github.libretube.util.deArrow
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -59,7 +60,7 @@ class TrendsFragment : Fragment() {
|
|||||||
val response = try {
|
val response = try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val region = LocaleHelper.getTrendingRegion(requireContext())
|
val region = LocaleHelper.getTrendingRegion(requireContext())
|
||||||
RetrofitInstance.api.getTrending(region)
|
RetrofitInstance.api.getTrending(region).deArrow()
|
||||||
}
|
}
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
println(e)
|
println(e)
|
||||||
|
89
app/src/main/java/com/github/libretube/util/DeArrowUtil.kt
Normal file
89
app/src/main/java/com/github/libretube/util/DeArrowUtil.kt
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package com.github.libretube.util
|
||||||
|
|
||||||
|
import android.util.Log
|
||||||
|
import com.github.libretube.api.JsonHelper
|
||||||
|
import com.github.libretube.api.RetrofitInstance
|
||||||
|
import com.github.libretube.api.obj.ContentItem
|
||||||
|
import com.github.libretube.api.obj.DeArrowContent
|
||||||
|
import com.github.libretube.api.obj.StreamItem
|
||||||
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
|
import com.github.libretube.extensions.toID
|
||||||
|
import com.github.libretube.helpers.PreferenceHelper
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import kotlinx.serialization.json.decodeFromJsonElement
|
||||||
|
|
||||||
|
object DeArrowUtil {
|
||||||
|
private fun extractTitleAndThumbnail(data: JsonElement): Pair<String?, String?> {
|
||||||
|
val content = try {
|
||||||
|
JsonHelper.json.decodeFromJsonElement<DeArrowContent>(data)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null to null
|
||||||
|
}
|
||||||
|
val newTitle = content.titles.maxByOrNull { it.votes }?.title
|
||||||
|
val newThumbnail =
|
||||||
|
content.thumbnails.filter { it.thumbnail != null }.maxByOrNull { it.votes }
|
||||||
|
?.takeIf { !it.original }?.thumbnail
|
||||||
|
return newTitle to newThumbnail
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the new titles and thumbnails generated by DeArrow to the stream items
|
||||||
|
*/
|
||||||
|
suspend fun deArrowStreamItems(streamItems: List<StreamItem>): List<StreamItem> {
|
||||||
|
if (!PreferenceHelper.getBoolean(PreferenceKeys.DEARROW, false)) return streamItems
|
||||||
|
|
||||||
|
val videoIds = streamItems.mapNotNull { it.url?.toID() }.joinToString(",")
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getDeArrowContent(videoIds)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(this::class.java.name, e.toString())
|
||||||
|
return streamItems
|
||||||
|
}
|
||||||
|
for ((videoId, data) in response.entries) {
|
||||||
|
val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
|
||||||
|
val streamItem = streamItems.firstOrNull { it.url?.toID() == videoId }
|
||||||
|
newTitle?.let { streamItem?.title = newTitle }
|
||||||
|
newThumbnail?.let { streamItem?.thumbnail = newThumbnail }
|
||||||
|
}
|
||||||
|
return streamItems
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the new titles and thumbnails generated by DeArrow to the stream items
|
||||||
|
*/
|
||||||
|
suspend fun deArrowContentItems(contentItems: List<ContentItem>): List<ContentItem> {
|
||||||
|
if (!PreferenceHelper.getBoolean(PreferenceKeys.DEARROW, false)) return contentItems
|
||||||
|
|
||||||
|
val videoIds = contentItems.filter { it.type == "stream" }
|
||||||
|
.joinToString(",") { it.url.toID() }
|
||||||
|
if (videoIds.isEmpty()) return contentItems
|
||||||
|
|
||||||
|
val response = try {
|
||||||
|
RetrofitInstance.api.getDeArrowContent(videoIds)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Log.e(this::class.java.name, e.toString())
|
||||||
|
return contentItems
|
||||||
|
}
|
||||||
|
for ((videoId, data) in response.entries) {
|
||||||
|
val (newTitle, newThumbnail) = extractTitleAndThumbnail(data)
|
||||||
|
val contentItem = contentItems.firstOrNull { it.url.toID() == videoId }
|
||||||
|
newTitle?.let { contentItem?.title = newTitle }
|
||||||
|
newThumbnail?.let { contentItem?.thumbnail = newThumbnail }
|
||||||
|
}
|
||||||
|
return contentItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If enabled in the preferences, this overrides the video's thumbnail and title with the one
|
||||||
|
* provided by the DeArrow project
|
||||||
|
*/
|
||||||
|
@JvmName("deArrowStreamItems")
|
||||||
|
suspend fun List<StreamItem>.deArrow() = DeArrowUtil.deArrowStreamItems(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If enabled in the preferences, this overrides the video's thumbnail and title with the one
|
||||||
|
* provided by the DeArrow project
|
||||||
|
*/
|
||||||
|
@JvmName("deArrowContentItems")
|
||||||
|
suspend fun List<ContentItem>.deArrow() = DeArrowUtil.deArrowContentItems(this)
|
@ -433,6 +433,9 @@
|
|||||||
<string name="visible">Show in seek bar</string>
|
<string name="visible">Show in seek bar</string>
|
||||||
<string name="fallback_piped_proxy">Fallback to Piped proxy</string>
|
<string name="fallback_piped_proxy">Fallback to Piped proxy</string>
|
||||||
<string name="fallback_piped_proxy_desc">Load videos via the proxy if connecting to YouTube directly doesn\'t work for the current video (increases the initial loading times). If disabled, YouTube music content likely won\'t play due to YT restrictions.</string>
|
<string name="fallback_piped_proxy_desc">Load videos via the proxy if connecting to YouTube directly doesn\'t work for the current video (increases the initial loading times). If disabled, YouTube music content likely won\'t play due to YT restrictions.</string>
|
||||||
|
<string name="dearrow">Enable DeArrow</string>
|
||||||
|
<string name="dearrow_summary">Show more accurate and less sensationalist titles and thumbnails. Increases loading times.</string>
|
||||||
|
|
||||||
<!-- Backup & Restore Settings -->
|
<!-- Backup & Restore Settings -->
|
||||||
<string name="import_subscriptions_from">Import subscriptions from</string>
|
<string name="import_subscriptions_from">Import subscriptions from</string>
|
||||||
<string name="export_subscriptions_to">Export subscriptions to</string>
|
<string name="export_subscriptions_to">Export subscriptions to</string>
|
||||||
|
@ -24,6 +24,12 @@
|
|||||||
app:key="sb_show_markers"
|
app:key="sb_show_markers"
|
||||||
app:title="@string/sb_markers" />
|
app:title="@string/sb_markers" />
|
||||||
|
|
||||||
|
<SwitchPreferenceCompat
|
||||||
|
app:defaultValue="false"
|
||||||
|
app:key="dearrow"
|
||||||
|
app:summary="@string/dearrow_summary"
|
||||||
|
app:title="@string/dearrow" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
app:defaultValue="true"
|
app:defaultValue="true"
|
||||||
app:key="sb_highlights"
|
app:key="sb_highlights"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user