mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-04-27 15:30:31 +05:30
Merge pull request #2755 from Isira-Seneviratne/KotlinX_Serialization
Switch to Kotlinx Serialization.
This commit is contained in:
commit
dd1821ada3
@ -4,6 +4,7 @@ plugins {
|
||||
id 'com.android.application'
|
||||
id 'kotlin-android'
|
||||
id 'kotlin-kapt'
|
||||
id 'kotlinx-serialization'
|
||||
}
|
||||
|
||||
android {
|
||||
@ -107,10 +108,11 @@ dependencies {
|
||||
implementation libs.exoplayer.extension.mediasession
|
||||
implementation libs.exoplayer.dash
|
||||
|
||||
/* Retrofit and Jackson */
|
||||
/* Retrofit and Kotlinx Serialization */
|
||||
implementation libs.square.retrofit
|
||||
implementation libs.square.retrofit.converterJackson
|
||||
implementation libs.jacksonAnnotations
|
||||
implementation libs.kotlinx.serialization
|
||||
implementation libs.kotlinx.datetime
|
||||
implementation libs.kotlinx.serialization.retrofit
|
||||
|
||||
/* Cronet and Coil */
|
||||
coreLibraryDesugaring libs.desugaring
|
||||
|
23
app/proguard-rules.pro
vendored
23
app/proguard-rules.pro
vendored
@ -29,3 +29,26 @@
|
||||
# Keep data classes used for Retrofit
|
||||
-keep class com.github.libretube.obj.** { *; }
|
||||
-keep class com.github.libretube.obj.update.** { *; }
|
||||
|
||||
# Keep rules required by Kotlinx Serialization
|
||||
-if @kotlinx.serialization.Serializable class **
|
||||
-keepclassmembers class <1> {
|
||||
static <1>$Companion Companion;
|
||||
}
|
||||
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
static **$* *;
|
||||
}
|
||||
-keepclassmembers class <2>$<3> {
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
-if @kotlinx.serialization.Serializable class ** {
|
||||
public static ** INSTANCE;
|
||||
}
|
||||
-keepclassmembers class <1> {
|
||||
public static <1> INSTANCE;
|
||||
kotlinx.serialization.KSerializer serializer(...);
|
||||
}
|
||||
|
||||
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
|
||||
|
9
app/src/main/java/com/github/libretube/api/JsonHelper.kt
Normal file
9
app/src/main/java/com/github/libretube/api/JsonHelper.kt
Normal file
@ -0,0 +1,9 @@
|
||||
package com.github.libretube.api
|
||||
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
object JsonHelper {
|
||||
val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ import com.github.libretube.api.obj.SegmentData
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import com.github.libretube.api.obj.Subscribe
|
||||
import com.github.libretube.api.obj.Subscribed
|
||||
import com.github.libretube.api.obj.Subscription
|
||||
import com.github.libretube.api.obj.Token
|
||||
import retrofit2.http.Body
|
||||
@ -114,7 +115,7 @@ interface PipedApi {
|
||||
suspend fun isSubscribed(
|
||||
@Query("channelId") channelId: String,
|
||||
@Header("Authorization") token: String
|
||||
): com.github.libretube.api.obj.Subscribed
|
||||
): Subscribed
|
||||
|
||||
@GET("subscriptions")
|
||||
suspend fun subscriptions(@Header("Authorization") token: String): List<Subscription>
|
||||
|
@ -93,10 +93,7 @@ object PlaylistsHelper {
|
||||
}.last().playlist.id.toString()
|
||||
}
|
||||
val response = try {
|
||||
RetrofitInstance.authApi.createPlaylist(
|
||||
token,
|
||||
Playlists(name = playlistName)
|
||||
)
|
||||
RetrofitInstance.authApi.createPlaylist(token, Playlists(name = playlistName))
|
||||
} catch (e: IOException) {
|
||||
appContext.toastFromMainThread(R.string.unknown_error)
|
||||
return null
|
||||
@ -107,7 +104,7 @@ object PlaylistsHelper {
|
||||
}
|
||||
if (response.playlistId != null) {
|
||||
appContext.toastFromMainThread(R.string.playlistCreated)
|
||||
return response.playlistId!!
|
||||
return response.playlistId
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -141,13 +138,8 @@ object PlaylistsHelper {
|
||||
return true
|
||||
}
|
||||
|
||||
return RetrofitInstance.authApi.addToPlaylist(
|
||||
token,
|
||||
PlaylistId(
|
||||
playlistId = playlistId,
|
||||
videoIds = videos.toList().map { it.url!!.toID() }
|
||||
)
|
||||
).message == "ok"
|
||||
val playlist = PlaylistId(playlistId, videoIds = videos.map { it.url!!.toID() })
|
||||
return RetrofitInstance.authApi.addToPlaylist(token, playlist).message == "ok"
|
||||
}
|
||||
|
||||
suspend fun renamePlaylist(playlistId: String, newName: String): Boolean {
|
||||
@ -164,10 +156,7 @@ object PlaylistsHelper {
|
||||
|
||||
return RetrofitInstance.authApi.renamePlaylist(
|
||||
token,
|
||||
PlaylistId(
|
||||
playlistId = playlistId,
|
||||
newName = newName
|
||||
)
|
||||
PlaylistId(playlistId, newName = newName)
|
||||
).playlistId != null
|
||||
}
|
||||
|
||||
@ -251,8 +240,8 @@ object PlaylistsHelper {
|
||||
name = list.name,
|
||||
type = "playlist",
|
||||
visibility = "private",
|
||||
videos = list.relatedStreams.orEmpty().map {
|
||||
YOUTUBE_FRONTEND_URL + "/watch?v=" + it.url!!.toID()
|
||||
videos = list.relatedStreams.map {
|
||||
"$YOUTUBE_FRONTEND_URL/watch?v=${it.url!!.toID()}"
|
||||
}
|
||||
)
|
||||
)
|
||||
@ -278,19 +267,13 @@ object PlaylistsHelper {
|
||||
val newPlaylist = createPlaylist(playlist.name ?: "Unknown name", appContext)
|
||||
newPlaylist ?: return@launch
|
||||
|
||||
addToPlaylist(
|
||||
newPlaylist,
|
||||
*playlist.relatedStreams.orEmpty().toTypedArray()
|
||||
)
|
||||
addToPlaylist(newPlaylist, *playlist.relatedStreams.toTypedArray())
|
||||
|
||||
var nextPage = playlist.nextpage
|
||||
while (nextPage != null) {
|
||||
nextPage = try {
|
||||
RetrofitInstance.api.getPlaylistNextPage(playlistId, nextPage).apply {
|
||||
addToPlaylist(
|
||||
newPlaylist,
|
||||
*relatedStreams.orEmpty().toTypedArray()
|
||||
)
|
||||
addToPlaylist(newPlaylist, *relatedStreams.toTypedArray())
|
||||
}.nextpage
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
|
@ -3,40 +3,43 @@ package com.github.libretube.api
|
||||
import com.github.libretube.constants.PIPED_API_URL
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||
import okhttp3.MediaType.Companion.toMediaType
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.jackson.JacksonConverterFactory
|
||||
import retrofit2.create
|
||||
|
||||
object RetrofitInstance {
|
||||
lateinit var url: String
|
||||
lateinit var authUrl: String
|
||||
val lazyMgr = resettableManager()
|
||||
val jacksonConverterFactory = JacksonConverterFactory.create()
|
||||
private val kotlinxConverterFactory = JsonHelper.json
|
||||
.asConverterFactory("application/json".toMediaType())
|
||||
|
||||
val api: PipedApi by resettableLazy(lazyMgr) {
|
||||
val api by resettableLazy(lazyMgr) {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(url)
|
||||
.callFactory(CronetHelper.callFactory)
|
||||
.addConverterFactory(jacksonConverterFactory)
|
||||
.addConverterFactory(kotlinxConverterFactory)
|
||||
.build()
|
||||
.create(PipedApi::class.java)
|
||||
.create<PipedApi>()
|
||||
}
|
||||
|
||||
val authApi: PipedApi by resettableLazy(lazyMgr) {
|
||||
val authApi by resettableLazy(lazyMgr) {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(authUrl)
|
||||
.callFactory(CronetHelper.callFactory)
|
||||
.addConverterFactory(jacksonConverterFactory)
|
||||
.addConverterFactory(kotlinxConverterFactory)
|
||||
.build()
|
||||
.create(PipedApi::class.java)
|
||||
.create<PipedApi>()
|
||||
}
|
||||
|
||||
val externalApi: ExternalApi by resettableLazy(lazyMgr) {
|
||||
val externalApi by resettableLazy(lazyMgr) {
|
||||
Retrofit.Builder()
|
||||
.baseUrl(url)
|
||||
.callFactory(CronetHelper.callFactory)
|
||||
.addConverterFactory(jacksonConverterFactory)
|
||||
.addConverterFactory(kotlinxConverterFactory)
|
||||
.build()
|
||||
.create(ExternalApi::class.java)
|
||||
.create<ExternalApi>()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.util.Log
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.obj.StreamItem
|
||||
import com.github.libretube.api.obj.Subscribe
|
||||
import com.github.libretube.api.obj.Subscription
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
@ -25,7 +26,7 @@ object SubscriptionHelper {
|
||||
try {
|
||||
RetrofitInstance.authApi.subscribe(
|
||||
PreferenceHelper.getToken(),
|
||||
com.github.libretube.api.obj.Subscribe(channelId)
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
@ -46,7 +47,7 @@ object SubscriptionHelper {
|
||||
try {
|
||||
RetrofitInstance.authApi.unsubscribe(
|
||||
PreferenceHelper.getToken(),
|
||||
com.github.libretube.api.obj.Subscribe(channelId)
|
||||
Subscribe(channelId)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
|
@ -1,17 +1,17 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Channel(
|
||||
var id: String? = null,
|
||||
var name: String? = null,
|
||||
var avatarUrl: String? = null,
|
||||
var bannerUrl: String? = null,
|
||||
var description: String? = null,
|
||||
var nextpage: String? = null,
|
||||
var subscriberCount: Long = 0,
|
||||
var verified: Boolean = false,
|
||||
var relatedStreams: List<StreamItem>? = listOf(),
|
||||
var tabs: List<ChannelTab>? = listOf()
|
||||
val id: String,
|
||||
val name: String,
|
||||
val avatarUrl: String,
|
||||
val bannerUrl: String,
|
||||
val description: String,
|
||||
val nextpage: String? = null,
|
||||
val subscriberCount: Long = 0,
|
||||
val verified: Boolean = false,
|
||||
val relatedStreams: List<StreamItem> = emptyList(),
|
||||
val tabs: List<ChannelTab> = emptyList()
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class ChannelTab(
|
||||
val name: String? = null,
|
||||
val data: String? = null
|
||||
val name: String,
|
||||
val data: String
|
||||
)
|
||||
|
@ -1,6 +1,9 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ChannelTabResponse(
|
||||
val content: List<ContentItem> = listOf(),
|
||||
val content: List<ContentItem> = emptyList(),
|
||||
val nextpage: String? = null
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class ChapterSegment(
|
||||
var title: String? = null,
|
||||
var image: String? = null,
|
||||
var start: Long? = null
|
||||
val title: String? = null,
|
||||
val image: String? = null,
|
||||
val start: Long? = null
|
||||
)
|
||||
|
@ -1,19 +1,19 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Comment(
|
||||
val author: String? = null,
|
||||
val commentId: String? = null,
|
||||
val commentText: String? = null,
|
||||
val commentedTime: String? = null,
|
||||
val commentorUrl: String? = null,
|
||||
val author: String,
|
||||
val commentId: String,
|
||||
val commentText: String,
|
||||
val commentedTime: String,
|
||||
val commentorUrl: String,
|
||||
val repliesPage: String? = null,
|
||||
val hearted: Boolean? = null,
|
||||
val likeCount: Long? = null,
|
||||
val pinned: Boolean? = null,
|
||||
val thumbnail: String? = null,
|
||||
val verified: Boolean? = null,
|
||||
val replyCount: Long? = null
|
||||
val hearted: Boolean,
|
||||
val likeCount: Long,
|
||||
val pinned: Boolean,
|
||||
val thumbnail: String,
|
||||
val verified: Boolean,
|
||||
val replyCount: Long
|
||||
)
|
||||
|
@ -1,10 +1,10 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class CommentsPage(
|
||||
var comments: MutableList<Comment> = arrayListOf(),
|
||||
val disabled: Boolean? = null,
|
||||
var comments: List<Comment> = emptyList(),
|
||||
val disabled: Boolean = false,
|
||||
val nextpage: String? = null
|
||||
)
|
||||
|
@ -1,28 +1,28 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class ContentItem(
|
||||
var url: String? = null,
|
||||
val type: String? = null,
|
||||
var thumbnail: String? = null,
|
||||
var uploaderName: String? = null,
|
||||
var uploaded: Long? = null,
|
||||
var shortDescription: String? = null,
|
||||
val url: String,
|
||||
val type: String,
|
||||
val thumbnail: String,
|
||||
val uploaderName: String? = null,
|
||||
val uploaded: Long? = null,
|
||||
val shortDescription: String? = null,
|
||||
// Video only attributes
|
||||
var title: String? = null,
|
||||
var uploaderUrl: String? = null,
|
||||
var uploaderAvatar: String? = null,
|
||||
var uploadedDate: String? = null,
|
||||
var duration: Long? = null,
|
||||
var views: Long? = null,
|
||||
var isShort: Boolean? = null,
|
||||
var uploaderVerified: Boolean? = null,
|
||||
val title: String? = null,
|
||||
val uploaderUrl: String? = null,
|
||||
val uploaderAvatar: String? = null,
|
||||
val uploadedDate: String? = null,
|
||||
val duration: Long = -1,
|
||||
val views: Long = -1,
|
||||
val isShort: Boolean? = null,
|
||||
val uploaderVerified: Boolean? = null,
|
||||
// Channel and Playlist attributes
|
||||
var name: String? = null,
|
||||
var description: String? = null,
|
||||
var subscribers: Long? = -1,
|
||||
var videos: Long? = -1,
|
||||
var verified: Boolean? = null
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val subscribers: Long = -1,
|
||||
val videos: Long = -1,
|
||||
val verified: Boolean? = null
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
data class DeleteUserRequest(
|
||||
var password: String? = null
|
||||
)
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class DeleteUserRequest(val password: String)
|
||||
|
@ -1,15 +1,16 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Instances(
|
||||
var name: String? = null,
|
||||
var api_url: String? = null,
|
||||
var locations: String? = null,
|
||||
var version: String? = null,
|
||||
var up_to_date: Boolean? = null,
|
||||
var cdn: Boolean? = null,
|
||||
var registered: Long? = null,
|
||||
var last_checked: Long? = null
|
||||
val name: String,
|
||||
@SerialName("api_url") val apiUrl: String,
|
||||
val locations: String,
|
||||
val version: String,
|
||||
@SerialName("up_to_date") val upToDate: Boolean,
|
||||
val cdn: Boolean,
|
||||
val registered: Long,
|
||||
@SerialName("last_checked") val lastChecked: Long
|
||||
)
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Login(
|
||||
val username: String? = null,
|
||||
val password: String? = null
|
||||
val username: String,
|
||||
val password: String
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
data class Message(
|
||||
var message: String? = null
|
||||
)
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class Message(val message: String? = null)
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class PipedConfig(
|
||||
val donationUrl: String? = null,
|
||||
val statusPageUrl: String? = null,
|
||||
|
@ -1,23 +1,23 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class PipedStream(
|
||||
var url: String? = null,
|
||||
var format: String? = null,
|
||||
var quality: String? = null,
|
||||
var mimeType: String? = null,
|
||||
var codec: String? = null,
|
||||
var videoOnly: Boolean? = null,
|
||||
var bitrate: Int? = null,
|
||||
var initStart: Int? = null,
|
||||
var initEnd: Int? = null,
|
||||
var indexStart: Int? = null,
|
||||
var indexEnd: Int? = null,
|
||||
var width: Int? = null,
|
||||
var height: Int? = null,
|
||||
var fps: Int? = null,
|
||||
val url: String? = null,
|
||||
val format: String? = null,
|
||||
val quality: String? = null,
|
||||
val mimeType: String? = null,
|
||||
val codec: String? = null,
|
||||
val videoOnly: Boolean? = null,
|
||||
val bitrate: Int? = null,
|
||||
val initStart: Int? = null,
|
||||
val initEnd: Int? = null,
|
||||
val indexStart: Int? = null,
|
||||
val indexEnd: Int? = null,
|
||||
val width: Int? = null,
|
||||
val height: Int? = null,
|
||||
val fps: Int? = null,
|
||||
val audioTrackName: String? = null,
|
||||
val audioTrackId: String? = null
|
||||
)
|
||||
|
@ -1,16 +1,16 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Playlist(
|
||||
var name: String? = null,
|
||||
var thumbnailUrl: String? = null,
|
||||
var bannerUrl: String? = null,
|
||||
var nextpage: String? = null,
|
||||
var uploader: String? = null,
|
||||
var uploaderUrl: String? = null,
|
||||
var uploaderAvatar: String? = null,
|
||||
var videos: Int? = 0,
|
||||
var relatedStreams: List<StreamItem>? = null
|
||||
val name: String? = null,
|
||||
val thumbnailUrl: String? = null,
|
||||
val bannerUrl: String? = null,
|
||||
val nextpage: String? = null,
|
||||
val uploader: String? = null,
|
||||
val uploaderUrl: String? = null,
|
||||
val uploaderAvatar: String? = null,
|
||||
val videos: Int = 0,
|
||||
val relatedStreams: List<StreamItem> = emptyList()
|
||||
)
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class PlaylistId(
|
||||
var playlistId: String? = null,
|
||||
var videoId: String? = null,
|
||||
var videoIds: List<String>? = null,
|
||||
var newName: String? = null,
|
||||
var index: Int = -1
|
||||
val playlistId: String? = null,
|
||||
val videoId: String? = null,
|
||||
val videoIds: List<String> = emptyList(),
|
||||
val newName: String? = null,
|
||||
val index: Int = -1
|
||||
)
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Playlists(
|
||||
var id: String? = null,
|
||||
var name: String? = null,
|
||||
var shortDescription: String? = null,
|
||||
var thumbnail: String? = null,
|
||||
var videos: Long? = null
|
||||
val id: String? = null,
|
||||
val name: String? = null,
|
||||
val shortDescription: String? = null,
|
||||
val thumbnail: String? = null,
|
||||
val videos: Long = 0
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class PreviewFrames(
|
||||
val urls: List<String>? = null,
|
||||
val frameWidth: Int? = null,
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class SearchResult(
|
||||
val items: MutableList<ContentItem>? = arrayListOf(),
|
||||
val items: List<ContentItem> = emptyList(),
|
||||
val nextpage: String? = null,
|
||||
val suggestion: String? = "",
|
||||
val suggestion: String? = null,
|
||||
val corrected: Boolean? = null
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Segment(
|
||||
val UUID: String? = null,
|
||||
val actionType: String? = null,
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class SegmentData(
|
||||
val hash: String? = null,
|
||||
val segments: List<Segment> = listOf(),
|
||||
|
@ -1,21 +1,21 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class StreamItem(
|
||||
var url: String? = null,
|
||||
val url: String? = null,
|
||||
val type: String? = null,
|
||||
var title: String? = null,
|
||||
var thumbnail: String? = null,
|
||||
var uploaderName: String? = null,
|
||||
var uploaderUrl: String? = null,
|
||||
var uploaderAvatar: String? = null,
|
||||
var uploadedDate: String? = null,
|
||||
var duration: Long? = null,
|
||||
var views: Long? = null,
|
||||
var uploaderVerified: Boolean? = null,
|
||||
var uploaded: Long? = null,
|
||||
var shortDescription: String? = null,
|
||||
val title: String? = null,
|
||||
val thumbnail: String? = null,
|
||||
val uploaderName: String? = null,
|
||||
val uploaderUrl: String? = null,
|
||||
val uploaderAvatar: String? = null,
|
||||
val uploadedDate: String? = null,
|
||||
val duration: Long? = null,
|
||||
val views: Long? = null,
|
||||
val uploaderVerified: Boolean? = null,
|
||||
val uploaded: Long? = null,
|
||||
val shortDescription: String? = null,
|
||||
val isShort: Boolean = false
|
||||
)
|
||||
|
@ -1,31 +1,32 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Streams(
|
||||
val title: String? = null,
|
||||
val description: String? = null,
|
||||
val uploadDate: String? = null,
|
||||
val uploader: String? = null,
|
||||
val uploaderUrl: String? = null,
|
||||
val uploaderAvatar: String? = null,
|
||||
val thumbnailUrl: String? = null,
|
||||
val title: String,
|
||||
val description: String,
|
||||
val uploadDate: LocalDate,
|
||||
val uploader: String,
|
||||
val uploaderUrl: String,
|
||||
val uploaderAvatar: String,
|
||||
val thumbnailUrl: String,
|
||||
val hls: String? = null,
|
||||
val dash: String? = null,
|
||||
val lbryId: String? = null,
|
||||
val uploaderVerified: Boolean? = null,
|
||||
val duration: Long? = null,
|
||||
val views: Long? = null,
|
||||
val likes: Long? = null,
|
||||
val dislikes: Long? = null,
|
||||
val audioStreams: List<PipedStream>? = null,
|
||||
val videoStreams: List<PipedStream>? = null,
|
||||
val relatedStreams: List<StreamItem>? = null,
|
||||
val subtitles: List<Subtitle>? = null,
|
||||
val livestream: Boolean? = null,
|
||||
val uploaderVerified: Boolean,
|
||||
val duration: Long,
|
||||
val views: Long = 0,
|
||||
val likes: Long = 0,
|
||||
val dislikes: Long = 0,
|
||||
val audioStreams: List<PipedStream> = emptyList(),
|
||||
val videoStreams: List<PipedStream> = emptyList(),
|
||||
val relatedStreams: List<StreamItem> = emptyList(),
|
||||
val subtitles: List<Subtitle> = emptyList(),
|
||||
val livestream: Boolean = false,
|
||||
val proxyUrl: String? = null,
|
||||
val chapters: List<ChapterSegment>? = null,
|
||||
val uploaderSubscriberCount: Long? = null,
|
||||
val previewFrames: List<PreviewFrames>? = null
|
||||
val chapters: List<ChapterSegment> = emptyList(),
|
||||
val uploaderSubscriberCount: Long = 0,
|
||||
val previewFrames: List<PreviewFrames> = emptyList()
|
||||
)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class Subscribe(
|
||||
var channelId: String? = null
|
||||
)
|
||||
@Serializable
|
||||
data class Subscribe(val channelId: String)
|
||||
|
@ -1,8 +1,6 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class Subscribed(
|
||||
var subscribed: Boolean? = null
|
||||
)
|
||||
@Serializable
|
||||
data class Subscribed(val subscribed: Boolean? = null)
|
||||
|
@ -1,11 +1,11 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Subscription(
|
||||
var url: String? = null,
|
||||
var name: String? = null,
|
||||
var avatar: String? = null,
|
||||
var verified: Boolean? = null
|
||||
val url: String,
|
||||
val name: String,
|
||||
val avatar: String,
|
||||
val verified: Boolean
|
||||
)
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Subtitle(
|
||||
val url: String? = null,
|
||||
val mimeType: String? = null,
|
||||
|
@ -1,9 +1,9 @@
|
||||
package com.github.libretube.api.obj
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Token(
|
||||
var token: String? = null,
|
||||
var error: String? = null
|
||||
val token: String? = null,
|
||||
val error: String? = null
|
||||
)
|
||||
|
@ -16,9 +16,9 @@ object DatabaseHelper {
|
||||
val watchHistoryItem = WatchHistoryItem(
|
||||
videoId,
|
||||
streams.title,
|
||||
streams.uploadDate,
|
||||
streams.uploadDate.toString(),
|
||||
streams.uploader,
|
||||
streams.uploaderUrl!!.toID(),
|
||||
streams.uploaderUrl.toID(),
|
||||
streams.uploaderAvatar,
|
||||
streams.thumbnailUrl,
|
||||
streams.duration
|
||||
|
@ -3,7 +3,9 @@ package com.github.libretube.db.obj
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "customInstance")
|
||||
class CustomInstance(
|
||||
@PrimaryKey var name: String = "",
|
||||
|
@ -2,7 +2,9 @@ package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity
|
||||
data class LocalPlaylist(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
|
@ -3,7 +3,9 @@ package com.github.libretube.db.obj
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity
|
||||
data class LocalPlaylistItem(
|
||||
@PrimaryKey(autoGenerate = true) val id: Int = 0,
|
||||
|
@ -2,7 +2,9 @@ package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Embedded
|
||||
import androidx.room.Relation
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LocalPlaylistWithVideos(
|
||||
@Embedded val playlist: LocalPlaylist = LocalPlaylist(),
|
||||
@Relation(
|
||||
|
@ -2,7 +2,9 @@ package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "localSubscription")
|
||||
data class LocalSubscription(
|
||||
@PrimaryKey val channelId: String = ""
|
||||
|
@ -2,7 +2,9 @@ package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "playlistBookmark")
|
||||
data class PlaylistBookmark(
|
||||
@PrimaryKey
|
||||
|
@ -2,7 +2,9 @@ package com.github.libretube.db.obj
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "searchHistoryItem")
|
||||
data class SearchHistoryItem(
|
||||
@PrimaryKey val query: String = ""
|
||||
|
@ -3,7 +3,9 @@ package com.github.libretube.db.obj
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "watchHistoryItem")
|
||||
data class WatchHistoryItem(
|
||||
@PrimaryKey val videoId: String = "",
|
||||
|
@ -3,7 +3,9 @@ package com.github.libretube.db.obj
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
@Entity(tableName = "watchPosition")
|
||||
data class WatchPosition(
|
||||
@PrimaryKey val videoId: String = "",
|
||||
|
@ -13,7 +13,7 @@ fun Streams.toStreamItem(videoId: String): StreamItem {
|
||||
uploaderName = uploader,
|
||||
uploaderUrl = uploaderUrl,
|
||||
uploaderAvatar = uploaderAvatar,
|
||||
uploadedDate = uploadDate,
|
||||
uploadedDate = uploadDate.toString(),
|
||||
uploaded = null,
|
||||
duration = duration,
|
||||
views = views,
|
||||
|
@ -7,14 +7,16 @@ import com.github.libretube.db.obj.PlaylistBookmark
|
||||
import com.github.libretube.db.obj.SearchHistoryItem
|
||||
import com.github.libretube.db.obj.WatchHistoryItem
|
||||
import com.github.libretube.db.obj.WatchPosition
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class BackupFile(
|
||||
var watchHistory: List<WatchHistoryItem>? = null,
|
||||
var watchPositions: List<WatchPosition>? = null,
|
||||
var searchHistory: List<SearchHistoryItem>? = null,
|
||||
var localSubscriptions: List<LocalSubscription>? = null,
|
||||
var customInstances: List<CustomInstance>? = null,
|
||||
var playlistBookmarks: List<PlaylistBookmark>? = null,
|
||||
var localPlaylists: List<LocalPlaylistWithVideos>? = null,
|
||||
var preferences: List<PreferenceItem>? = null
|
||||
var watchHistory: List<WatchHistoryItem> = emptyList(),
|
||||
var watchPositions: List<WatchPosition> = emptyList(),
|
||||
var searchHistory: List<SearchHistoryItem> = emptyList(),
|
||||
var localSubscriptions: List<LocalSubscription> = emptyList(),
|
||||
var customInstances: List<CustomInstance> = emptyList(),
|
||||
var playlistBookmarks: List<PlaylistBookmark> = emptyList(),
|
||||
var localPlaylists: List<LocalPlaylistWithVideos> = emptyList(),
|
||||
var preferences: List<PreferenceItem> = emptyList()
|
||||
)
|
||||
|
@ -1,5 +1,8 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ImportPlaylist(
|
||||
var name: String? = null,
|
||||
val type: String? = null,
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ImportPlaylistFile(
|
||||
val format: String? = null,
|
||||
val version: Int? = null,
|
||||
val playlists: List<ImportPlaylist>? = null
|
||||
val format: String,
|
||||
val version: Int,
|
||||
val playlists: List<ImportPlaylist> = emptyList()
|
||||
)
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class NewPipeSubscription(
|
||||
val name: String? = null,
|
||||
val service_id: Int? = null,
|
||||
val url: String? = null
|
||||
val name: String,
|
||||
@SerialName("service_id") val serviceId: Int,
|
||||
val url: String
|
||||
)
|
||||
|
@ -1,7 +1,11 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class NewPipeSubscriptions(
|
||||
val app_version: String = "",
|
||||
val app_version_int: Int = 0,
|
||||
val subscriptions: List<NewPipeSubscription>? = null
|
||||
@SerialName("app_version") val appVersion: String = "",
|
||||
@SerialName("app_version_int") val appVersionInt: Int = 0,
|
||||
val subscriptions: List<NewPipeSubscription> = emptyList()
|
||||
)
|
||||
|
@ -1,6 +1,11 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
|
||||
@Serializable
|
||||
data class PreferenceItem(
|
||||
val key: String? = null,
|
||||
val value: Any? = null
|
||||
val value: JsonPrimitive = JsonNull
|
||||
)
|
||||
|
@ -1,20 +1,24 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Asset(
|
||||
val browser_download_url: String? = null,
|
||||
val content_type: String? = null,
|
||||
val created_at: String? = null,
|
||||
val download_count: Int? = null,
|
||||
val id: Int? = null,
|
||||
val label: Any? = null,
|
||||
val name: String? = null,
|
||||
val node_id: String? = null,
|
||||
val size: Int? = null,
|
||||
val state: String? = null,
|
||||
val updated_at: String? = null,
|
||||
val uploader: Uploader? = null,
|
||||
val url: String? = null
|
||||
@SerialName("browser_download_url") val browserDownloadUrl: String,
|
||||
@SerialName("content_type") val contentType: String,
|
||||
@SerialName("created_at") val createdAt: Instant,
|
||||
@SerialName("download_count") val downloadCount: Int,
|
||||
val id: Int,
|
||||
val label: JsonElement = JsonNull,
|
||||
val name: String,
|
||||
@SerialName("node_id") val nodeId: String,
|
||||
val size: Int,
|
||||
val state: String,
|
||||
@SerialName("updated_at") val updatedAt: Instant,
|
||||
val uploader: User,
|
||||
val url: String
|
||||
)
|
||||
|
@ -1,25 +0,0 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class Author(
|
||||
val avatar_url: String? = null,
|
||||
val events_url: String? = null,
|
||||
val followers_url: String? = null,
|
||||
val following_url: String? = null,
|
||||
val gists_url: String? = null,
|
||||
val gravatar_id: String? = null,
|
||||
val html_url: String? = null,
|
||||
val id: Int? = null,
|
||||
val login: String? = null,
|
||||
val node_id: String? = null,
|
||||
val organizations_url: String? = null,
|
||||
val received_events_url: String? = null,
|
||||
val repos_url: String? = null,
|
||||
val site_admin: Boolean? = null,
|
||||
val starred_url: String? = null,
|
||||
val subscriptions_url: String? = null,
|
||||
val type: String? = null,
|
||||
val url: String? = null
|
||||
)
|
@ -1,15 +1,16 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class Reactions(
|
||||
val confused: Int? = null,
|
||||
val eyes: Int? = null,
|
||||
val heart: Int? = null,
|
||||
val hooray: Int? = null,
|
||||
val laugh: Int? = null,
|
||||
val rocket: Int? = null,
|
||||
val total_count: Int? = null,
|
||||
val url: String? = null
|
||||
val confused: Int,
|
||||
val eyes: Int,
|
||||
val heart: Int,
|
||||
val hooray: Int,
|
||||
val laugh: Int,
|
||||
val rocket: Int,
|
||||
@SerialName("total_count") val totalCount: Int,
|
||||
val url: String
|
||||
)
|
||||
|
@ -1,27 +1,29 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@Serializable
|
||||
data class UpdateInfo(
|
||||
val assets: List<Asset>? = null,
|
||||
val assets_url: String? = null,
|
||||
val author: Author? = null,
|
||||
val body: String? = null,
|
||||
val created_at: String? = null,
|
||||
val draft: Boolean? = null,
|
||||
val html_url: String? = null,
|
||||
val id: Int? = null,
|
||||
val mentions_count: Int? = null,
|
||||
val name: String? = null,
|
||||
val node_id: String? = null,
|
||||
val prerelease: Boolean? = null,
|
||||
val published_at: String? = null,
|
||||
val reactions: Reactions? = null,
|
||||
val tag_name: String? = null,
|
||||
val tarball_url: String? = null,
|
||||
val target_commitish: String? = null,
|
||||
val upload_url: String? = null,
|
||||
val url: String? = null,
|
||||
val zipball_url: String? = null
|
||||
val assets: List<Asset> = emptyList(),
|
||||
@SerialName("assets_url") val assetsUrl: String,
|
||||
val author: User,
|
||||
val body: String,
|
||||
@SerialName("created_at") val createdAt: Instant,
|
||||
val draft: Boolean,
|
||||
@SerialName("html_url") val htmlUrl: String,
|
||||
val id: Int,
|
||||
@SerialName("mentions_count") val mentionsCount: Int,
|
||||
val name: String,
|
||||
@SerialName("node_id") val nodeId: String,
|
||||
val prerelease: Boolean,
|
||||
@SerialName("published_at") val publishedAt: Instant,
|
||||
val reactions: Reactions,
|
||||
@SerialName("tag_name") val tagName: String,
|
||||
@SerialName("tarball_url") val tarballUrl: String,
|
||||
@SerialName("target_commitish") val targetCommitish: String,
|
||||
@SerialName("upload_url") val uploadUrl: String,
|
||||
val url: String,
|
||||
@SerialName("zipball_url") val zipballUrl: String
|
||||
)
|
||||
|
@ -1,25 +0,0 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
data class Uploader(
|
||||
val avatar_url: String? = null,
|
||||
val events_url: String? = null,
|
||||
val followers_url: String? = null,
|
||||
val following_url: String? = null,
|
||||
val gists_url: String? = null,
|
||||
val gravatar_id: String? = null,
|
||||
val html_url: String? = null,
|
||||
val id: Int? = null,
|
||||
val login: String? = null,
|
||||
val node_id: String? = null,
|
||||
val organizations_url: String? = null,
|
||||
val received_events_url: String? = null,
|
||||
val repos_url: String? = null,
|
||||
val site_admin: Boolean? = null,
|
||||
val starred_url: String? = null,
|
||||
val subscriptions_url: String? = null,
|
||||
val type: String? = null,
|
||||
val url: String? = null
|
||||
)
|
26
app/src/main/java/com/github/libretube/obj/update/User.kt
Normal file
26
app/src/main/java/com/github/libretube/obj/update/User.kt
Normal file
@ -0,0 +1,26 @@
|
||||
package com.github.libretube.obj.update
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class User(
|
||||
@SerialName("avatar_url") val avatarUrl: String,
|
||||
@SerialName("events_url") val eventsUrl: String,
|
||||
@SerialName("followers_url") val followersUrl: String,
|
||||
@SerialName("following_url") val followingUrl: String,
|
||||
@SerialName("gists_url") val gistsUrl: String,
|
||||
@SerialName("gravatar_id") val gravatarId: String,
|
||||
@SerialName("html_url") val htmlUrl: String,
|
||||
val id: Int,
|
||||
val login: String,
|
||||
@SerialName("node_id") val nodeId: String,
|
||||
@SerialName("organizations_url") val organizationsUrl: String,
|
||||
@SerialName("received_events_url") val receivedEventsUrl: String,
|
||||
@SerialName("repos_url") val reposUrl: String,
|
||||
@SerialName("site_admin") val siteAdmin: Boolean,
|
||||
@SerialName("starred_url") val starredUrl: String,
|
||||
@SerialName("subscriptions_url") val subscriptionsUrl: String,
|
||||
val type: String,
|
||||
val url: String
|
||||
)
|
@ -13,8 +13,8 @@ import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ServiceCompat
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.JsonHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.Segment
|
||||
import com.github.libretube.api.obj.SegmentData
|
||||
@ -40,6 +40,7 @@ import com.google.android.exoplayer2.Player
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.encodeToString
|
||||
|
||||
/**
|
||||
* Loads the selected videos audio in background mode with a notification area.
|
||||
@ -318,10 +319,9 @@ class BackgroundMode : Service() {
|
||||
runCatching {
|
||||
val categories = PlayerHelper.getSponsorBlockCategories()
|
||||
if (categories.isEmpty()) return@runCatching
|
||||
segmentData =
|
||||
RetrofitInstance.api.getSegments(
|
||||
segmentData = RetrofitInstance.api.getSegments(
|
||||
videoId,
|
||||
ObjectMapper().writeValueAsString(categories)
|
||||
JsonHelper.json.encodeToString(categories)
|
||||
)
|
||||
checkForSegments()
|
||||
}
|
||||
|
@ -102,21 +102,19 @@ class DownloadService : Service() {
|
||||
Database.downloadDao().insertDownload(
|
||||
Download(
|
||||
videoId = videoId,
|
||||
title = streams.title ?: "",
|
||||
title = streams.title,
|
||||
thumbnailPath = thumbnailTargetFile.absolutePath,
|
||||
description = streams.description ?: "",
|
||||
uploadDate = streams.uploadDate,
|
||||
uploader = streams.uploader ?: ""
|
||||
description = streams.description,
|
||||
uploadDate = streams.uploadDate.toString(),
|
||||
uploader = streams.uploader
|
||||
)
|
||||
)
|
||||
}
|
||||
streams.thumbnailUrl?.let { url ->
|
||||
ImageHelper.downloadImage(
|
||||
this@DownloadService,
|
||||
url,
|
||||
streams.thumbnailUrl,
|
||||
thumbnailTargetFile.absolutePath
|
||||
)
|
||||
}
|
||||
|
||||
val downloadItems = streams.toDownloadItems(
|
||||
videoId,
|
||||
|
@ -66,22 +66,21 @@ class CommentsAdapter(
|
||||
commentorImage.scaleY = REPLIES_ADAPTER_SCALE
|
||||
}
|
||||
|
||||
commentInfos.text =
|
||||
comment.author.toString() + TextUtils.SEPARATOR + comment.commentedTime.toString()
|
||||
commentInfos.text = comment.author + TextUtils.SEPARATOR + comment.commentedTime
|
||||
commentText.text = HtmlCompat.fromHtml(
|
||||
comment.commentText.toString(),
|
||||
comment.commentText,
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
|
||||
ImageHelper.loadImage(comment.thumbnail, commentorImage)
|
||||
likesTextView.text = comment.likeCount.formatShort()
|
||||
|
||||
if (comment.verified == true) verifiedImageView.visibility = View.VISIBLE
|
||||
if (comment.pinned == true) pinnedImageView.visibility = View.VISIBLE
|
||||
if (comment.hearted == true) heartedImageView.visibility = View.VISIBLE
|
||||
if (comment.verified) verifiedImageView.visibility = View.VISIBLE
|
||||
if (comment.pinned) pinnedImageView.visibility = View.VISIBLE
|
||||
if (comment.hearted) heartedImageView.visibility = View.VISIBLE
|
||||
if (comment.repliesPage != null) repliesAvailable.visibility = View.VISIBLE
|
||||
if ((comment.replyCount ?: -1L) > 0L) {
|
||||
repliesCount.text = comment.replyCount?.formatShort()
|
||||
if (comment.replyCount > 0L) {
|
||||
repliesCount.text = comment.replyCount.formatShort()
|
||||
}
|
||||
|
||||
commentorImage.setOnClickListener {
|
||||
@ -99,7 +98,7 @@ class CommentsAdapter(
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
ClipboardHelper(root.context).save(comment.commentText.toString())
|
||||
ClipboardHelper(root.context).save(comment.commentText)
|
||||
Toast.makeText(root.context, R.string.copied, Toast.LENGTH_SHORT).show()
|
||||
true
|
||||
}
|
||||
|
@ -83,13 +83,13 @@ class SearchAdapter(
|
||||
private fun bindWatch(item: ContentItem, binding: VideoRowBinding) {
|
||||
binding.apply {
|
||||
ImageHelper.loadImage(item.thumbnail, thumbnail)
|
||||
thumbnailDuration.setFormattedDuration(item.duration!!, item.isShort)
|
||||
thumbnailDuration.setFormattedDuration(item.duration, item.isShort)
|
||||
ImageHelper.loadImage(item.uploaderAvatar, channelImage)
|
||||
videoTitle.text = item.title
|
||||
val viewsString = if (item.views?.toInt() != -1) item.views.formatShort() else ""
|
||||
val uploadDate = if (item.uploadedDate != null) item.uploadedDate else ""
|
||||
val viewsString = if (item.views != -1L) item.views.formatShort() else ""
|
||||
val uploadDate = item.uploadedDate.orEmpty()
|
||||
videoInfo.text =
|
||||
if (viewsString != "" && uploadDate != "") {
|
||||
if (viewsString.isNotEmpty() && uploadDate.isNotEmpty()) {
|
||||
"$viewsString • $uploadDate"
|
||||
} else {
|
||||
viewsString + uploadDate
|
||||
@ -98,7 +98,7 @@ class SearchAdapter(
|
||||
root.setOnClickListener {
|
||||
NavigationHelper.navigateVideo(root.context, item.url)
|
||||
}
|
||||
val videoId = item.url!!.toID()
|
||||
val videoId = item.url.toID()
|
||||
val videoName = item.title!!
|
||||
root.setOnLongClickListener {
|
||||
VideoOptionsBottomSheet(videoId, videoName)
|
||||
@ -111,7 +111,7 @@ class SearchAdapter(
|
||||
channelContainer.setOnClickListener {
|
||||
NavigationHelper.navigateChannel(root.context, item.uploaderUrl)
|
||||
}
|
||||
watchProgress.setWatchProgressLength(videoId, item.duration!!)
|
||||
watchProgress.setWatchProgressLength(videoId, item.duration)
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,12 +135,12 @@ class SearchAdapter(
|
||||
}
|
||||
|
||||
root.setOnLongClickListener {
|
||||
ChannelOptionsBottomSheet(item.url!!.toID(), item.name)
|
||||
ChannelOptionsBottomSheet(item.url.toID(), item.name)
|
||||
.show((root.context as BaseActivity).supportFragmentManager)
|
||||
true
|
||||
}
|
||||
|
||||
binding.searchSubButton.setupSubscriptionButton(item.url?.toID(), item.name?.toID())
|
||||
binding.searchSubButton.setupSubscriptionButton(item.url.toID(), item.name?.toID())
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ class SearchAdapter(
|
||||
) {
|
||||
binding.apply {
|
||||
ImageHelper.loadImage(item.thumbnail, playlistThumbnail)
|
||||
if (item.videos?.toInt() != -1) videoCount.text = item.videos.toString()
|
||||
if (item.videos != -1L) videoCount.text = item.videos.toString()
|
||||
playlistTitle.text = item.name
|
||||
playlistDescription.text = item.uploaderName
|
||||
root.setOnClickListener {
|
||||
@ -158,7 +158,7 @@ class SearchAdapter(
|
||||
}
|
||||
deletePlaylist.visibility = View.GONE
|
||||
root.setOnLongClickListener {
|
||||
val playlistId = item.url!!.toID()
|
||||
val playlistId = item.url.toID()
|
||||
val playlistName = item.name!!
|
||||
PlaylistOptionsBottomSheet(playlistId, playlistName, PlaylistType.PUBLIC)
|
||||
.show(
|
||||
|
@ -11,6 +11,8 @@ import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.obj.PreferenceItem
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.serialization.json.JsonNull
|
||||
import kotlinx.serialization.json.JsonPrimitive
|
||||
|
||||
class BackupDialog(
|
||||
private val createBackupFile: (BackupFile) -> Unit
|
||||
@ -45,8 +47,14 @@ class BackupDialog(
|
||||
})
|
||||
|
||||
object Preferences : BackupOption(R.string.preferences, onSelected = { file ->
|
||||
file.preferences = PreferenceHelper.settings.all.map {
|
||||
PreferenceItem(it.key, it.value)
|
||||
file.preferences = PreferenceHelper.settings.all.map { (key, value) ->
|
||||
val jsonValue = when (value) {
|
||||
is Number -> JsonPrimitive(value)
|
||||
is Boolean -> JsonPrimitive(value)
|
||||
is String -> JsonPrimitive(value)
|
||||
else -> JsonNull
|
||||
}
|
||||
PreferenceItem(key, jsonValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import androidx.fragment.app.DialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.DeleteUserRequest
|
||||
import com.github.libretube.databinding.DialogDeleteAccountBinding
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.util.PreferenceHelper
|
||||
@ -41,10 +42,7 @@ class DeleteAccountDialog : DialogFragment() {
|
||||
val token = PreferenceHelper.getToken()
|
||||
|
||||
try {
|
||||
RetrofitInstance.authApi.deleteAccount(
|
||||
token,
|
||||
com.github.libretube.api.obj.DeleteUserRequest(password)
|
||||
)
|
||||
RetrofitInstance.authApi.deleteAccount(token, DeleteUserRequest(password))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
|
||||
|
@ -74,7 +74,7 @@ class DownloadDialog(
|
||||
}
|
||||
|
||||
private fun initDownloadOptions(streams: Streams) {
|
||||
binding.fileName.setText(streams.title.toString())
|
||||
binding.fileName.setText(streams.title)
|
||||
|
||||
val vidName = arrayListOf<String>()
|
||||
|
||||
@ -82,7 +82,7 @@ class DownloadDialog(
|
||||
vidName.add(getString(R.string.no_video))
|
||||
|
||||
// add all available video streams
|
||||
for (vid in streams.videoStreams!!) {
|
||||
for (vid in streams.videoStreams) {
|
||||
if (vid.url != null) {
|
||||
val name = vid.quality + " " + vid.format
|
||||
vidName.add(name)
|
||||
@ -95,7 +95,7 @@ class DownloadDialog(
|
||||
audioName.add(getString(R.string.no_audio))
|
||||
|
||||
// add all available audio streams
|
||||
for (audio in streams.audioStreams!!) {
|
||||
for (audio in streams.audioStreams) {
|
||||
if (audio.url != null) {
|
||||
val name = audio.quality + " " + audio.format
|
||||
audioName.add(name)
|
||||
@ -108,7 +108,7 @@ class DownloadDialog(
|
||||
subtitleName.add(getString(R.string.no_subtitle))
|
||||
|
||||
// add all available subtitles
|
||||
for (subtitle in streams.subtitles!!) {
|
||||
for (subtitle in streams.subtitles) {
|
||||
if (subtitle.url != null) {
|
||||
subtitleName.add(subtitle.name.toString())
|
||||
}
|
||||
|
@ -92,8 +92,8 @@ class LoginDialog : DialogFragment() {
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
|
||||
PreferenceHelper.setToken(response.token!!)
|
||||
PreferenceHelper.setUsername(login.username!!)
|
||||
PreferenceHelper.setToken(response.token)
|
||||
PreferenceHelper.setUsername(login.username)
|
||||
|
||||
dialog?.dismiss()
|
||||
activity?.recreate()
|
||||
|
@ -29,7 +29,7 @@ class UpdateDialog(
|
||||
intent.putExtra("downloadUrl", downloadUrl)
|
||||
context?.startService(intent)
|
||||
} else {
|
||||
val uri = Uri.parse(updateInfo.html_url)
|
||||
val uri = Uri.parse(updateInfo.htmlUrl)
|
||||
val intent = Intent(Intent.ACTION_VIEW).setData(uri)
|
||||
startActivity(intent)
|
||||
}
|
||||
@ -40,8 +40,10 @@ class UpdateDialog(
|
||||
private fun getDownloadUrl(updateInfo: UpdateInfo): String? {
|
||||
val supportedArchitectures = Build.SUPPORTED_ABIS
|
||||
supportedArchitectures.forEach { arch ->
|
||||
updateInfo.assets?.forEach { asset ->
|
||||
if (asset.name?.contains(arch) == true) return asset.browser_download_url
|
||||
updateInfo.assets.forEach { asset ->
|
||||
if (asset.name.contains(arch)) {
|
||||
return asset.browserDownloadUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
|
@ -142,7 +142,7 @@ class ChannelFragment : BaseFragment() {
|
||||
|
||||
binding.channelShare.setOnClickListener {
|
||||
val shareDialog = ShareDialog(
|
||||
response.id!!.toID(),
|
||||
response.id.toID(),
|
||||
ShareObjectType.CHANNEL,
|
||||
shareData
|
||||
)
|
||||
@ -169,10 +169,10 @@ class ChannelFragment : BaseFragment() {
|
||||
R.string.subscribers,
|
||||
response.subscriberCount.formatShort()
|
||||
)
|
||||
if (response.description?.trim() == "") {
|
||||
if (response.description.isBlank()) {
|
||||
binding.channelDescription.visibility = View.GONE
|
||||
} else {
|
||||
binding.channelDescription.text = response.description?.trim()
|
||||
binding.channelDescription.text = response.description.trim()
|
||||
}
|
||||
|
||||
binding.channelDescription.setOnClickListener {
|
||||
@ -186,13 +186,13 @@ class ChannelFragment : BaseFragment() {
|
||||
|
||||
// recyclerview of the videos by the channel
|
||||
channelAdapter = VideosAdapter(
|
||||
response.relatedStreams.orEmpty().toMutableList(),
|
||||
response.relatedStreams.toMutableList(),
|
||||
forceMode = VideosAdapter.Companion.ForceMode.CHANNEL
|
||||
)
|
||||
binding.channelRecView.adapter = channelAdapter
|
||||
}
|
||||
|
||||
response.tabs?.let { setupTabs(it) }
|
||||
setupTabs(response.tabs)
|
||||
}
|
||||
}
|
||||
|
||||
@ -230,16 +230,13 @@ class ChannelFragment : BaseFragment() {
|
||||
|
||||
private fun loadTab(tab: ChannelTab) {
|
||||
scope.launch {
|
||||
tab.data ?: return@launch
|
||||
val response = try {
|
||||
RetrofitInstance.api.getChannelTab(tab.data)
|
||||
} catch (e: Exception) {
|
||||
return@launch
|
||||
}
|
||||
|
||||
val adapter = SearchAdapter(
|
||||
response.content.toMutableList()
|
||||
)
|
||||
val adapter = SearchAdapter(response.content.toMutableList())
|
||||
|
||||
runOnUiThread {
|
||||
binding.channelRecView.adapter = adapter
|
||||
@ -275,7 +272,7 @@ class ChannelFragment : BaseFragment() {
|
||||
return@launchWhenCreated
|
||||
}
|
||||
nextPage = response.nextpage
|
||||
channelAdapter?.insertItems(response.relatedStreams.orEmpty())
|
||||
channelAdapter?.insertItems(response.relatedStreams)
|
||||
isLoading = false
|
||||
binding.channelRefresh.isRefreshing = false
|
||||
}
|
||||
@ -291,9 +288,9 @@ class ChannelFragment : BaseFragment() {
|
||||
) {
|
||||
scope.launch {
|
||||
val newContent = try {
|
||||
RetrofitInstance.api.getChannelTab(tab.data ?: "", nextPage)
|
||||
RetrofitInstance.api.getChannelTab(tab.data, nextPage)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG(), "Exception: $e")
|
||||
null
|
||||
}
|
||||
onNewNextPage.invoke(newContent?.nextpage)
|
||||
|
@ -37,9 +37,9 @@ import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.CronetHelper
|
||||
import com.github.libretube.api.JsonHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.obj.ChapterSegment
|
||||
import com.github.libretube.api.obj.PipedStream
|
||||
@ -119,6 +119,8 @@ import kotlin.math.abs
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.serialization.encodeToString
|
||||
import org.chromium.net.CronetEngine
|
||||
import retrofit2.HttpException
|
||||
|
||||
@ -685,9 +687,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
} else {
|
||||
PlayingQueue.updateCurrent(streams.toStreamItem(videoId!!))
|
||||
if (PlayerHelper.autoInsertRelatedVideos) {
|
||||
PlayingQueue.add(
|
||||
*streams.relatedStreams.orEmpty().toTypedArray()
|
||||
)
|
||||
PlayingQueue.add(*streams.relatedStreams.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -748,7 +748,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
segmentData =
|
||||
RetrofitInstance.api.getSegments(
|
||||
videoId!!,
|
||||
ObjectMapper().writeValueAsString(categories)
|
||||
JsonHelper.json.encodeToString(categories)
|
||||
)
|
||||
if (segmentData.segments.isEmpty()) return@runCatching
|
||||
playerBinding.exoProgress.setSegments(segmentData.segments)
|
||||
@ -776,8 +776,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
playerBinding.liveDiff.text = "-$diffText"
|
||||
}
|
||||
// call the function again after 100ms
|
||||
handler
|
||||
.postDelayed(this@PlayerFragment::refreshLiveStatus, 100)
|
||||
handler.postDelayed(this@PlayerFragment::refreshLiveStatus, 100)
|
||||
}
|
||||
|
||||
// seek to saved watch position if available
|
||||
@ -797,7 +796,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
return
|
||||
}
|
||||
// position is almost the end of the video => don't seek, start from beginning
|
||||
if (position != null && position < streams.duration!! * 1000 * 0.9) {
|
||||
if (position != null && position < streams.duration * 1000 * 0.9) {
|
||||
exoPlayer.seekTo(position)
|
||||
}
|
||||
}
|
||||
@ -826,7 +825,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
playerBinding.exoProgress.setPlayer(exoPlayer)
|
||||
}
|
||||
|
||||
private fun localizedDate(date: String?): String? {
|
||||
private fun localizedDate(date: LocalDate): String {
|
||||
val locale = ConfigurationCompat.getLocales(resources.configuration)[0]!!
|
||||
return TextUtils.localizeDate(date, locale)
|
||||
}
|
||||
@ -870,12 +869,12 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
playerChannelSubCount.text = context?.getString(
|
||||
R.string.subscribers,
|
||||
streams.uploaderSubscriberCount?.formatShort()
|
||||
streams.uploaderSubscriberCount.formatShort()
|
||||
)
|
||||
}
|
||||
|
||||
// duration that's not greater than 0 indicates that the video is live
|
||||
if (streams.duration!! <= 0) {
|
||||
if (streams.duration <= 0) {
|
||||
isLive = true
|
||||
handleLiveVideo()
|
||||
}
|
||||
@ -883,10 +882,8 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
playerBinding.exoTitle.text = streams.title
|
||||
|
||||
// init the chapters recyclerview
|
||||
if (streams.chapters != null) {
|
||||
chapters = streams.chapters.orEmpty()
|
||||
chapters = streams.chapters
|
||||
initializeChapters()
|
||||
}
|
||||
|
||||
// Listener for play and pause icon change
|
||||
exoPlayer.addListener(object : Player.Listener {
|
||||
@ -972,7 +969,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
})
|
||||
|
||||
binding.relPlayerDownload.setOnClickListener {
|
||||
if (streams.duration!! <= 0) {
|
||||
if (streams.duration <= 0) {
|
||||
Toast.makeText(context, R.string.cannotDownload, Toast.LENGTH_SHORT).show()
|
||||
} else if (!DownloadService.IS_DOWNLOAD_RUNNING) {
|
||||
val newFragment = DownloadDialog(videoId!!)
|
||||
@ -995,7 +992,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
}
|
||||
initializeRelatedVideos(streams.relatedStreams)
|
||||
// set video description
|
||||
val description = streams.description!!
|
||||
val description = streams.description
|
||||
|
||||
setupDescription(binding.playerDescription, description)
|
||||
|
||||
@ -1009,7 +1006,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
|
||||
// update the subscribed state
|
||||
binding.playerSubscribe.setupSubscriptionButton(
|
||||
this.streams.uploaderUrl?.toID(),
|
||||
this.streams.uploaderUrl.toID(),
|
||||
this.streams.uploader
|
||||
)
|
||||
|
||||
@ -1268,9 +1265,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
private fun setResolutionAndSubtitles() {
|
||||
// create a list of subtitles
|
||||
subtitles = mutableListOf()
|
||||
val subtitlesNamesList = mutableListOf(context?.getString(R.string.none)!!)
|
||||
val subtitlesNamesList = mutableListOf(getString(R.string.none))
|
||||
val subtitleCodesList = mutableListOf("")
|
||||
streams.subtitles.orEmpty().forEach {
|
||||
streams.subtitles.forEach {
|
||||
subtitles.add(
|
||||
SubtitleConfiguration.Builder(it.url!!.toUri())
|
||||
.setMimeType(it.mimeType!!) // The correct MIME type (required).
|
||||
@ -1300,7 +1297,7 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
if (defaultResolution != "") setPlayerResolution(defaultResolution.toInt())
|
||||
|
||||
if (!PreferenceHelper.getBoolean(PreferenceKeys.USE_HLS_OVER_DASH, false) &&
|
||||
streams.videoStreams.orEmpty().isNotEmpty()
|
||||
streams.videoStreams.isNotEmpty()
|
||||
) {
|
||||
val uri = let {
|
||||
streams.dash?.toUri()
|
||||
@ -1377,16 +1374,14 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
}
|
||||
|
||||
override fun onCaptionsClicked() {
|
||||
if (!this@PlayerFragment::streams.isInitialized ||
|
||||
streams.subtitles.isNullOrEmpty()
|
||||
) {
|
||||
if (!this@PlayerFragment::streams.isInitialized || streams.subtitles.isEmpty()) {
|
||||
Toast.makeText(context, R.string.no_subtitles_available, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
val subtitlesNamesList = mutableListOf(context?.getString(R.string.none)!!)
|
||||
val subtitlesNamesList = mutableListOf(getString(R.string.none))
|
||||
val subtitleCodesList = mutableListOf("")
|
||||
streams.subtitles!!.forEach {
|
||||
streams.subtitles.forEach {
|
||||
subtitlesNamesList += it.name!!
|
||||
subtitleCodesList += it.code!!
|
||||
}
|
||||
@ -1515,9 +1510,9 @@ class PlayerFragment : BaseFragment(), OnlinePlayerOptions {
|
||||
playerBinding.seekbarPreview.visibility = View.GONE
|
||||
playerBinding.exoProgress.addListener(
|
||||
SeekbarPreviewListener(
|
||||
streams.previewFrames.orEmpty(),
|
||||
streams.previewFrames,
|
||||
playerBinding.seekbarPreview,
|
||||
streams.duration!! * 1000
|
||||
streams.duration * 1000
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ class PlaylistFragment : BaseFragment() {
|
||||
Log.e(TAG(), e.toString())
|
||||
return@launchWhenCreated
|
||||
}
|
||||
playlistFeed = response.relatedStreams.orEmpty().toMutableList()
|
||||
playlistFeed = response.relatedStreams.toMutableList()
|
||||
binding.playlistScrollview.visibility = View.VISIBLE
|
||||
nextPage = response.nextpage
|
||||
playlistName = response.name
|
||||
@ -140,7 +140,7 @@ class PlaylistFragment : BaseFragment() {
|
||||
if (playlistFeed.isEmpty()) return@setOnClickListener
|
||||
NavigationHelper.navigateVideo(
|
||||
requireContext(),
|
||||
response.relatedStreams!!.first().url?.toID(),
|
||||
response.relatedStreams.first().url?.toID(),
|
||||
playlistId
|
||||
)
|
||||
}
|
||||
@ -279,15 +279,9 @@ class PlaylistFragment : BaseFragment() {
|
||||
val response = try {
|
||||
// load locally stored playlists with the auth api
|
||||
if (playlistType == PlaylistType.PRIVATE) {
|
||||
RetrofitInstance.authApi.getPlaylistNextPage(
|
||||
playlistId!!,
|
||||
nextPage!!
|
||||
)
|
||||
RetrofitInstance.authApi.getPlaylistNextPage(playlistId!!, nextPage!!)
|
||||
} else {
|
||||
RetrofitInstance.api.getPlaylistNextPage(
|
||||
playlistId!!,
|
||||
nextPage!!
|
||||
)
|
||||
RetrofitInstance.api.getPlaylistNextPage(playlistId!!, nextPage!!)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG(), e.toString())
|
||||
@ -295,7 +289,7 @@ class PlaylistFragment : BaseFragment() {
|
||||
}
|
||||
|
||||
nextPage = response.nextpage
|
||||
playlistAdapter?.updateItems(response.relatedStreams!!)
|
||||
playlistAdapter?.updateItems(response.relatedStreams)
|
||||
isLoading = false
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.github.libretube.R
|
||||
@ -94,13 +95,9 @@ class SearchResultFragment : BaseFragment() {
|
||||
return@launchWhenCreated
|
||||
}
|
||||
runOnUiThread {
|
||||
searchAdapter = SearchAdapter(response.items.orEmpty().toMutableList())
|
||||
searchAdapter = SearchAdapter(response.items.toMutableList())
|
||||
binding.searchRecycler.adapter = searchAdapter
|
||||
binding.noSearchResult.visibility = if (response.items.orEmpty().isEmpty()) {
|
||||
View.VISIBLE
|
||||
} else {
|
||||
View.GONE
|
||||
}
|
||||
binding.noSearchResult.isVisible = response.items.isEmpty()
|
||||
}
|
||||
nextPage = response.nextpage
|
||||
}
|
||||
@ -124,8 +121,8 @@ class SearchResultFragment : BaseFragment() {
|
||||
}
|
||||
nextPage = response.nextpage!!
|
||||
kotlin.runCatching {
|
||||
if (response.items?.isNotEmpty() == true) {
|
||||
searchAdapter.updateItems(response.items.toMutableList())
|
||||
if (response.items.isNotEmpty()) {
|
||||
searchAdapter.updateItems(response.items)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ class CommentsViewModel : ViewModel() {
|
||||
return@launch
|
||||
}
|
||||
val updatedPage = commentsPage.value?.apply {
|
||||
comments = comments.plus(response.comments).toMutableList()
|
||||
comments += response.comments
|
||||
}
|
||||
nextPage = response.nextpage
|
||||
commentsPage.postValue(updatedPage)
|
||||
|
@ -68,7 +68,7 @@ class BackupRestoreSettings : BasePreferenceFragment() {
|
||||
createBackupFile = registerForActivityResult(
|
||||
CreateDocument("application/json")
|
||||
) { uri: Uri? ->
|
||||
BackupHelper(requireContext()).advancedBackup(uri, backupFile)
|
||||
BackupHelper(requireContext()).createAdvancedBackup(uri, backupFile)
|
||||
}
|
||||
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -137,8 +137,8 @@ class InstanceSettings : BasePreferenceFragment() {
|
||||
|
||||
response?.sortBy { it.name }
|
||||
|
||||
instanceNames.addAll(response.orEmpty().map { it.name ?: "" })
|
||||
instanceValues.addAll(response.orEmpty().map { it.api_url ?: "" })
|
||||
instanceNames.addAll(response.orEmpty().map { it.name })
|
||||
instanceValues.addAll(response.orEmpty().map { it.apiUrl })
|
||||
|
||||
customInstances.forEach { instance ->
|
||||
instanceNames += instance.name
|
||||
|
@ -20,7 +20,7 @@ import kotlinx.coroutines.runBlocking
|
||||
*/
|
||||
class ChannelOptionsBottomSheet(
|
||||
private val channelId: String,
|
||||
private val channelName: String?
|
||||
channelName: String?
|
||||
) : BaseBottomSheet() {
|
||||
private val shareData = ShareData(currentChannel = channelName)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
@ -44,7 +44,7 @@ class ChannelOptionsBottomSheet(
|
||||
val channel = runBlocking {
|
||||
RetrofitInstance.api.getChannel(channelId)
|
||||
}
|
||||
channel.relatedStreams?.firstOrNull()?.url?.toID()?.let {
|
||||
channel.relatedStreams.firstOrNull()?.url?.toID()?.let {
|
||||
NavigationHelper.navigateVideo(
|
||||
requireContext(),
|
||||
it,
|
||||
@ -60,7 +60,7 @@ class ChannelOptionsBottomSheet(
|
||||
val channel = runBlocking {
|
||||
RetrofitInstance.api.getChannel(channelId)
|
||||
}
|
||||
channel.relatedStreams?.firstOrNull()?.url?.toID()?.let {
|
||||
channel.relatedStreams.firstOrNull()?.url?.toID()?.let {
|
||||
BackgroundHelper.playOnBackground(
|
||||
requireContext(),
|
||||
videoId = it,
|
||||
|
@ -2,15 +2,22 @@ package com.github.libretube.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.github.libretube.api.JsonHelper
|
||||
import com.github.libretube.constants.PreferenceKeys
|
||||
import com.github.libretube.db.DatabaseHolder.Companion.Database
|
||||
import com.github.libretube.extensions.TAG
|
||||
import com.github.libretube.extensions.query
|
||||
import com.github.libretube.obj.BackupFile
|
||||
import com.github.libretube.obj.PreferenceItem
|
||||
import java.io.FileOutputStream
|
||||
import kotlinx.serialization.json.booleanOrNull
|
||||
import kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import kotlinx.serialization.json.floatOrNull
|
||||
import kotlinx.serialization.json.intOrNull
|
||||
import kotlinx.serialization.json.longOrNull
|
||||
|
||||
/**
|
||||
* Backup and restore the preferences
|
||||
@ -19,18 +26,15 @@ class BackupHelper(private val context: Context) {
|
||||
/**
|
||||
* Write a [BackupFile] containing the database content as well as the preferences
|
||||
*/
|
||||
fun advancedBackup(uri: Uri?, backupFile: BackupFile) {
|
||||
if (uri == null) return
|
||||
fun createAdvancedBackup(uri: Uri?, backupFile: BackupFile) {
|
||||
uri?.let {
|
||||
try {
|
||||
context.contentResolver.openFileDescriptor(uri, "w")?.use {
|
||||
FileOutputStream(it.fileDescriptor).use { fileOutputStream ->
|
||||
fileOutputStream.write(
|
||||
ObjectMapper().writeValueAsBytes(backupFile)
|
||||
)
|
||||
}
|
||||
context.contentResolver.openOutputStream(it)?.use { outputStream ->
|
||||
JsonHelper.json.encodeToStream(backupFile, outputStream)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG(), "Error while writing backup: $e")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,36 +42,33 @@ class BackupHelper(private val context: Context) {
|
||||
* Restore data from a [BackupFile]
|
||||
*/
|
||||
fun restoreAdvancedBackup(uri: Uri?) {
|
||||
if (uri == null) return
|
||||
|
||||
val mapper = ObjectMapper()
|
||||
val json = context.contentResolver.openInputStream(uri)?.use {
|
||||
it.bufferedReader().use { reader -> reader.readText() }
|
||||
}.orEmpty()
|
||||
|
||||
val backupFile = mapper.readValue(json, BackupFile::class.java)
|
||||
val backupFile = uri?.let {
|
||||
context.contentResolver.openInputStream(it)?.use { inputStream ->
|
||||
JsonHelper.json.decodeFromStream<BackupFile>(inputStream)
|
||||
}
|
||||
} ?: return
|
||||
|
||||
query {
|
||||
Database.watchHistoryDao().insertAll(
|
||||
*backupFile.watchHistory.orEmpty().toTypedArray()
|
||||
*backupFile.watchHistory.toTypedArray()
|
||||
)
|
||||
Database.searchHistoryDao().insertAll(
|
||||
*backupFile.searchHistory.orEmpty().toTypedArray()
|
||||
*backupFile.searchHistory.toTypedArray()
|
||||
)
|
||||
Database.watchPositionDao().insertAll(
|
||||
*backupFile.watchPositions.orEmpty().toTypedArray()
|
||||
*backupFile.watchPositions.toTypedArray()
|
||||
)
|
||||
Database.localSubscriptionDao().insertAll(
|
||||
*backupFile.localSubscriptions.orEmpty().toTypedArray()
|
||||
*backupFile.localSubscriptions.toTypedArray()
|
||||
)
|
||||
Database.customInstanceDao().insertAll(
|
||||
*backupFile.customInstances.orEmpty().toTypedArray()
|
||||
*backupFile.customInstances.toTypedArray()
|
||||
)
|
||||
Database.playlistBookmarkDao().insertAll(
|
||||
*backupFile.playlistBookmarks.orEmpty().toTypedArray()
|
||||
*backupFile.playlistBookmarks.toTypedArray()
|
||||
)
|
||||
|
||||
backupFile.localPlaylists?.forEach {
|
||||
backupFile.localPlaylists.forEach {
|
||||
Database.localPlaylistsDao().createPlaylist(it.playlist)
|
||||
val playlistId = Database.localPlaylistsDao().getAll().last().playlist.id
|
||||
it.videos.forEach {
|
||||
@ -90,18 +91,26 @@ class BackupHelper(private val context: Context) {
|
||||
clear()
|
||||
|
||||
// decide for each preference which type it is and save it to the preferences
|
||||
preferences.forEach {
|
||||
when (it.value) {
|
||||
is Boolean -> putBoolean(it.key, it.value)
|
||||
is Float -> putFloat(it.key, it.value)
|
||||
is Long -> putLong(it.key, it.value)
|
||||
preferences.forEach { (key, jsonValue) ->
|
||||
val value = if (jsonValue.isString) {
|
||||
jsonValue.content
|
||||
} else {
|
||||
jsonValue.booleanOrNull
|
||||
?: jsonValue.intOrNull
|
||||
?: jsonValue.longOrNull
|
||||
?: jsonValue.floatOrNull
|
||||
}
|
||||
when (value) {
|
||||
is Boolean -> putBoolean(key, value)
|
||||
is Float -> putFloat(key, value)
|
||||
is Long -> putLong(key, value)
|
||||
is Int -> {
|
||||
when (it.key) {
|
||||
PreferenceKeys.START_FRAGMENT -> putInt(it.key, it.value)
|
||||
else -> putLong(it.key, it.value.toLong())
|
||||
when (key) {
|
||||
PreferenceKeys.START_FRAGMENT -> putInt(key, value)
|
||||
else -> putLong(key, value.toLong())
|
||||
}
|
||||
}
|
||||
is String -> putString(it.key, it.value)
|
||||
is String -> putString(key, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,8 @@ import android.app.Activity
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.JsonHelper
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
import com.github.libretube.api.RetrofitInstance
|
||||
import com.github.libretube.api.SubscriptionHelper
|
||||
@ -15,11 +15,13 @@ 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 kotlinx.serialization.json.decodeFromStream
|
||||
import kotlinx.serialization.json.encodeToStream
|
||||
import okio.use
|
||||
|
||||
class ImportHelper(
|
||||
private val activity: Activity
|
||||
@ -56,12 +58,11 @@ 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
|
||||
)
|
||||
subscriptions.subscriptions.orEmpty().map {
|
||||
it.url!!.replace("https://www.youtube.com/channel/", "")
|
||||
val subscriptions = activity.contentResolver.openInputStream(uri)?.use {
|
||||
JsonHelper.json.decodeFromStream<NewPipeSubscriptions>(it)
|
||||
}
|
||||
subscriptions?.subscriptions.orEmpty().map {
|
||||
it.url.replace("https://www.youtube.com/channel/", "")
|
||||
}
|
||||
}
|
||||
"text/csv", "text/comma-separated-values" -> {
|
||||
@ -91,20 +92,14 @@ class ImportHelper(
|
||||
SubscriptionHelper.getFormattedLocalSubscriptions()
|
||||
)
|
||||
}
|
||||
val newPipeChannels = mutableListOf<NewPipeSubscription>()
|
||||
subs.forEach {
|
||||
newPipeChannels += NewPipeSubscription(
|
||||
name = it.name,
|
||||
service_id = 0,
|
||||
url = "https://www.youtube.com" + it.url
|
||||
)
|
||||
val newPipeChannels = subs.map {
|
||||
NewPipeSubscription(it.name, 0, "https://www.youtube.com${it.url}")
|
||||
}
|
||||
val newPipeSubscriptions = NewPipeSubscriptions(subscriptions = newPipeChannels)
|
||||
|
||||
val newPipeSubscriptions = NewPipeSubscriptions(
|
||||
subscriptions = newPipeChannels
|
||||
)
|
||||
|
||||
uri.write(newPipeSubscriptions)
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(newPipeSubscriptions, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainThread(R.string.exportsuccess)
|
||||
}
|
||||
@ -134,11 +129,10 @@ class ImportHelper(
|
||||
}
|
||||
}
|
||||
"application/json", "application/*", "application/octet-stream" -> {
|
||||
val playlistFile = ObjectMapper().readValue(
|
||||
uri.readText(),
|
||||
ImportPlaylistFile::class.java
|
||||
)
|
||||
importPlaylists.addAll(playlistFile.playlists.orEmpty())
|
||||
val playlistFile = activity.contentResolver.openInputStream(uri)?.use {
|
||||
JsonHelper.json.decodeFromStream<ImportPlaylistFile>(it)
|
||||
}
|
||||
importPlaylists.addAll(playlistFile?.playlists.orEmpty())
|
||||
}
|
||||
else -> {
|
||||
activity.applicationContext.toastFromMainThread("Unsupported file type $fileType")
|
||||
@ -167,31 +161,13 @@ class ImportHelper(
|
||||
|
||||
runBlocking {
|
||||
val playlists = PlaylistsHelper.exportPlaylists()
|
||||
val playlistFile = ImportPlaylistFile(
|
||||
format = "Piped",
|
||||
version = 1,
|
||||
playlists = playlists
|
||||
)
|
||||
val playlistFile = ImportPlaylistFile("Piped", 1, playlists)
|
||||
|
||||
uri.write(playlistFile)
|
||||
activity.contentResolver.openOutputStream(uri)?.use {
|
||||
JsonHelper.json.encodeToStream(playlistFile, it)
|
||||
}
|
||||
|
||||
activity.toastFromMainThread(R.string.exportsuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Uri.readText(): String {
|
||||
return activity.contentResolver.openInputStream(this)?.use {
|
||||
it.bufferedReader().use { reader -> reader.readText() }
|
||||
}.orEmpty()
|
||||
}
|
||||
|
||||
private fun Uri.write(text: Any) {
|
||||
activity.contentResolver.openFileDescriptor(this, "w")?.use {
|
||||
FileOutputStream(it.fileDescriptor).use { fileOutputStream ->
|
||||
fileOutputStream.write(
|
||||
ObjectMapper().writeValueAsBytes(text)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
package com.github.libretube.util
|
||||
|
||||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.github.libretube.api.obj.Streams
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
|
||||
class MetadataHelper(
|
||||
private val context: Context
|
||||
) {
|
||||
private val mapper = ObjectMapper()
|
||||
private val metadataDir = DownloadHelper.getDownloadDir(context, DownloadHelper.METADATA_DIR)
|
||||
|
||||
fun createMetadata(fileName: String, streams: Streams) {
|
||||
val targetFile = File(metadataDir, fileName)
|
||||
targetFile.createNewFile()
|
||||
|
||||
context.contentResolver.openFileDescriptor(
|
||||
Uri.fromFile(targetFile),
|
||||
"w"
|
||||
)?.use {
|
||||
FileOutputStream(it.fileDescriptor).use { fileOutputStream ->
|
||||
fileOutputStream.write(
|
||||
mapper.writeValueAsBytes(
|
||||
streams
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getMetadata(fileName: String): Streams? {
|
||||
val sourceFile = File(metadataDir, fileName)
|
||||
|
||||
return try {
|
||||
val json = context.contentResolver.openInputStream(
|
||||
Uri.fromFile(sourceFile)
|
||||
)?.use {
|
||||
it.bufferedReader().use { reader -> reader.readText() }
|
||||
}
|
||||
mapper.readValue(json, Streams::class.java)
|
||||
} catch (e: Exception) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
@ -147,7 +147,7 @@ object PlayingQueue {
|
||||
scope.launch {
|
||||
while (channelNextPage != null) {
|
||||
RetrofitInstance.api.getChannelNextPage(channelId, nextPage!!).apply {
|
||||
add(*relatedStreams.orEmpty().toTypedArray())
|
||||
add(*relatedStreams.toTypedArray())
|
||||
channelNextPage = this.nextpage
|
||||
}
|
||||
}
|
||||
@ -158,7 +158,7 @@ object PlayingQueue {
|
||||
scope.launch {
|
||||
runCatching {
|
||||
val channel = RetrofitInstance.api.getChannel(channelId)
|
||||
add(*channel.relatedStreams.orEmpty().toTypedArray())
|
||||
add(*channel.relatedStreams.toTypedArray())
|
||||
updateCurrent(newCurrentStream)
|
||||
if (channel.nextpage == null) return@launch
|
||||
fetchMoreFromChannel(channelId, channel.nextpage)
|
||||
|
@ -2,10 +2,11 @@ package com.github.libretube.util
|
||||
|
||||
import android.net.Uri
|
||||
import java.net.URL
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
import java.util.*
|
||||
import kotlinx.datetime.LocalDate
|
||||
import kotlinx.datetime.toJavaLocalDate
|
||||
|
||||
object TextUtils {
|
||||
/**
|
||||
@ -42,16 +43,9 @@ object TextUtils {
|
||||
* @param locale The locale to use, otherwise uses system default
|
||||
* return Localized date string
|
||||
*/
|
||||
fun localizeDate(date: String?, locale: Locale): String? {
|
||||
date ?: return null
|
||||
|
||||
// relative time span
|
||||
if (!date.contains("-")) return date
|
||||
|
||||
val dateObj = LocalDate.parse(date)
|
||||
|
||||
fun localizeDate(date: LocalDate, locale: Locale): String {
|
||||
val formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(locale)
|
||||
return dateObj.format(formatter)
|
||||
return date.toJavaLocalDate().format(formatter)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5,13 +5,15 @@
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.22'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.0'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
|
@ -11,13 +11,15 @@ espresso = "3.5.1"
|
||||
workRuntime = "2.7.1"
|
||||
exoplayer = "2.18.2"
|
||||
retrofit = "2.9.0"
|
||||
jacksonAnnotations = "2.13.4"
|
||||
desugaring = "2.0.0"
|
||||
cronetEmbedded = "108.5359.79"
|
||||
cronetOkHttp = "0.1.0"
|
||||
coil = "2.2.2"
|
||||
leakcanary = "2.10"
|
||||
room = "2.5.0"
|
||||
kotlinxSerialization = "1.4.1"
|
||||
kotlinxDatetime = "0.4.0"
|
||||
kotlinxRetrofit = "0.8.0"
|
||||
|
||||
[libraries]
|
||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||
@ -33,8 +35,6 @@ androidx-work-runtime = { group = "androidx.work", name="work-runtime-ktx", vers
|
||||
exoplayer = { group = "com.google.android.exoplayer", name = "exoplayer", version.ref = "exoplayer" }
|
||||
exoplayer-extension-mediasession = { group = "com.google.android.exoplayer", name = "extension-mediasession", version.ref = "exoplayer" }
|
||||
square-retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
||||
square-retrofit-converterJackson = { group = "com.squareup.retrofit2", name = "converter-jackson", version.ref = "retrofit" }
|
||||
jacksonAnnotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jacksonAnnotations" }
|
||||
desugaring = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "desugaring" }
|
||||
exoplayer-extension-cronet = { group = "com.google.android.exoplayer", name = "extension-cronet", version.ref = "exoplayer" }
|
||||
exoplayer-dash = { group = "com.google.android.exoplayer", name = "exoplayer-dash", version.ref = "exoplayer" }
|
||||
@ -47,3 +47,6 @@ lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-kt
|
||||
lifecycle-livedata = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycle" }
|
||||
room = { group = "androidx.room", name="room-runtime", version.ref = "room" }
|
||||
room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
|
||||
kotlinx-serialization = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerialization" }
|
||||
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" }
|
||||
kotlinx-serialization-retrofit = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "kotlinxRetrofit" }
|
Loading…
x
Reference in New Issue
Block a user