diff --git a/app/build.gradle b/app/build.gradle index d581b1574..71d600d86 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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 diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index db9143d05..c9ea8f734 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -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 diff --git a/app/src/main/java/com/github/libretube/api/JsonHelper.kt b/app/src/main/java/com/github/libretube/api/JsonHelper.kt new file mode 100644 index 000000000..bc44741c2 --- /dev/null +++ b/app/src/main/java/com/github/libretube/api/JsonHelper.kt @@ -0,0 +1,9 @@ +package com.github.libretube.api + +import kotlinx.serialization.json.Json + +object JsonHelper { + val json = Json { + ignoreUnknownKeys = true + } +} diff --git a/app/src/main/java/com/github/libretube/api/PipedApi.kt b/app/src/main/java/com/github/libretube/api/PipedApi.kt index 53400a9f5..98e032389 100644 --- a/app/src/main/java/com/github/libretube/api/PipedApi.kt +++ b/app/src/main/java/com/github/libretube/api/PipedApi.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt b/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt index add8856f9..2b1f58f8c 100644 --- a/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt +++ b/app/src/main/java/com/github/libretube/api/PlaylistsHelper.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/api/RetrofitInstance.kt b/app/src/main/java/com/github/libretube/api/RetrofitInstance.kt index 03f69cee7..743280989 100644 --- a/app/src/main/java/com/github/libretube/api/RetrofitInstance.kt +++ b/app/src/main/java/com/github/libretube/api/RetrofitInstance.kt @@ -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() } - 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() } - 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() } /** diff --git a/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt b/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt index 61f1c6cc5..571d23572 100644 --- a/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt +++ b/app/src/main/java/com/github/libretube/api/SubscriptionHelper.kt @@ -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()) diff --git a/app/src/main/java/com/github/libretube/api/obj/Channel.kt b/app/src/main/java/com/github/libretube/api/obj/Channel.kt index e1b261df4..5a227bea4 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Channel.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Channel.kt @@ -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? = listOf(), - var tabs: List? = 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 = emptyList(), + val tabs: List = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/api/obj/ChannelTab.kt b/app/src/main/java/com/github/libretube/api/obj/ChannelTab.kt index c7e2d63de..14e0f86cf 100644 --- a/app/src/main/java/com/github/libretube/api/obj/ChannelTab.kt +++ b/app/src/main/java/com/github/libretube/api/obj/ChannelTab.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/ChannelTabResponse.kt b/app/src/main/java/com/github/libretube/api/obj/ChannelTabResponse.kt index 6c6fd7bae..8208239a0 100644 --- a/app/src/main/java/com/github/libretube/api/obj/ChannelTabResponse.kt +++ b/app/src/main/java/com/github/libretube/api/obj/ChannelTabResponse.kt @@ -1,6 +1,9 @@ package com.github.libretube.api.obj +import kotlinx.serialization.Serializable + +@Serializable data class ChannelTabResponse( - val content: List = listOf(), + val content: List = emptyList(), val nextpage: String? = null ) diff --git a/app/src/main/java/com/github/libretube/api/obj/ChapterSegment.kt b/app/src/main/java/com/github/libretube/api/obj/ChapterSegment.kt index 6fbdfed00..c0fb3d7eb 100644 --- a/app/src/main/java/com/github/libretube/api/obj/ChapterSegment.kt +++ b/app/src/main/java/com/github/libretube/api/obj/ChapterSegment.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Comment.kt b/app/src/main/java/com/github/libretube/api/obj/Comment.kt index ef8f6f9c4..d21018e88 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Comment.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Comment.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/CommentsPage.kt b/app/src/main/java/com/github/libretube/api/obj/CommentsPage.kt index 88bb66a1b..3f8f83eec 100644 --- a/app/src/main/java/com/github/libretube/api/obj/CommentsPage.kt +++ b/app/src/main/java/com/github/libretube/api/obj/CommentsPage.kt @@ -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 = arrayListOf(), - val disabled: Boolean? = null, + var comments: List = emptyList(), + val disabled: Boolean = false, val nextpage: String? = null ) diff --git a/app/src/main/java/com/github/libretube/api/obj/ContentItem.kt b/app/src/main/java/com/github/libretube/api/obj/ContentItem.kt index 9d6f33652..7d1492a66 100644 --- a/app/src/main/java/com/github/libretube/api/obj/ContentItem.kt +++ b/app/src/main/java/com/github/libretube/api/obj/ContentItem.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/DeleteUserRequest.kt b/app/src/main/java/com/github/libretube/api/obj/DeleteUserRequest.kt index e4a961836..7b5e6735e 100644 --- a/app/src/main/java/com/github/libretube/api/obj/DeleteUserRequest.kt +++ b/app/src/main/java/com/github/libretube/api/obj/DeleteUserRequest.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/api/obj/Instances.kt b/app/src/main/java/com/github/libretube/api/obj/Instances.kt index 053cb8b63..a25777be7 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Instances.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Instances.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Login.kt b/app/src/main/java/com/github/libretube/api/obj/Login.kt index 0636d72d9..eb8411491 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Login.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Login.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Message.kt b/app/src/main/java/com/github/libretube/api/obj/Message.kt index 93f063af0..70692071a 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Message.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Message.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/api/obj/PipedConfig.kt b/app/src/main/java/com/github/libretube/api/obj/PipedConfig.kt index 1595b674f..e7f1c33ad 100644 --- a/app/src/main/java/com/github/libretube/api/obj/PipedConfig.kt +++ b/app/src/main/java/com/github/libretube/api/obj/PipedConfig.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/api/obj/PipedStream.kt b/app/src/main/java/com/github/libretube/api/obj/PipedStream.kt index 58de468e8..aadf7ed59 100644 --- a/app/src/main/java/com/github/libretube/api/obj/PipedStream.kt +++ b/app/src/main/java/com/github/libretube/api/obj/PipedStream.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Playlist.kt b/app/src/main/java/com/github/libretube/api/obj/Playlist.kt index 6530c04df..4933a91d8 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Playlist.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Playlist.kt @@ -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? = 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 = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/api/obj/PlaylistId.kt b/app/src/main/java/com/github/libretube/api/obj/PlaylistId.kt index ea10202a4..3b083deff 100644 --- a/app/src/main/java/com/github/libretube/api/obj/PlaylistId.kt +++ b/app/src/main/java/com/github/libretube/api/obj/PlaylistId.kt @@ -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? = null, - var newName: String? = null, - var index: Int = -1 + val playlistId: String? = null, + val videoId: String? = null, + val videoIds: List = emptyList(), + val newName: String? = null, + val index: Int = -1 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Playlists.kt b/app/src/main/java/com/github/libretube/api/obj/Playlists.kt index 9bee35d0e..bf5c4faa2 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Playlists.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Playlists.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/PreviewFrames.kt b/app/src/main/java/com/github/libretube/api/obj/PreviewFrames.kt index db7a051d4..48966998e 100644 --- a/app/src/main/java/com/github/libretube/api/obj/PreviewFrames.kt +++ b/app/src/main/java/com/github/libretube/api/obj/PreviewFrames.kt @@ -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? = null, val frameWidth: Int? = null, diff --git a/app/src/main/java/com/github/libretube/api/obj/SearchResult.kt b/app/src/main/java/com/github/libretube/api/obj/SearchResult.kt index f923a6c7f..8cdb45d56 100644 --- a/app/src/main/java/com/github/libretube/api/obj/SearchResult.kt +++ b/app/src/main/java/com/github/libretube/api/obj/SearchResult.kt @@ -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? = arrayListOf(), + val items: List = emptyList(), val nextpage: String? = null, - val suggestion: String? = "", + val suggestion: String? = null, val corrected: Boolean? = null ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Segment.kt b/app/src/main/java/com/github/libretube/api/obj/Segment.kt index 951a7b472..c1711e417 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Segment.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Segment.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/api/obj/SegmentData.kt b/app/src/main/java/com/github/libretube/api/obj/SegmentData.kt index a383cd801..4f65720af 100644 --- a/app/src/main/java/com/github/libretube/api/obj/SegmentData.kt +++ b/app/src/main/java/com/github/libretube/api/obj/SegmentData.kt @@ -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 = listOf(), diff --git a/app/src/main/java/com/github/libretube/api/obj/StreamItem.kt b/app/src/main/java/com/github/libretube/api/obj/StreamItem.kt index 9363fbabd..60dadc0b7 100644 --- a/app/src/main/java/com/github/libretube/api/obj/StreamItem.kt +++ b/app/src/main/java/com/github/libretube/api/obj/StreamItem.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Streams.kt b/app/src/main/java/com/github/libretube/api/obj/Streams.kt index f4c561b22..6f4f8ce85 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Streams.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Streams.kt @@ -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? = null, - val videoStreams: List? = null, - val relatedStreams: List? = null, - val subtitles: List? = 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 = emptyList(), + val videoStreams: List = emptyList(), + val relatedStreams: List = emptyList(), + val subtitles: List = emptyList(), + val livestream: Boolean = false, val proxyUrl: String? = null, - val chapters: List? = null, - val uploaderSubscriberCount: Long? = null, - val previewFrames: List? = null + val chapters: List = emptyList(), + val uploaderSubscriberCount: Long = 0, + val previewFrames: List = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Subscribe.kt b/app/src/main/java/com/github/libretube/api/obj/Subscribe.kt index f474e129b..d268df2ca 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Subscribe.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Subscribe.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/api/obj/Subscribed.kt b/app/src/main/java/com/github/libretube/api/obj/Subscribed.kt index f20324e50..94986ec23 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Subscribed.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Subscribed.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/api/obj/Subscription.kt b/app/src/main/java/com/github/libretube/api/obj/Subscription.kt index 5ddcf0861..b6dbf323b 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Subscription.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Subscription.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/api/obj/Subtitle.kt b/app/src/main/java/com/github/libretube/api/obj/Subtitle.kt index 74454e802..91b6760cd 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Subtitle.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Subtitle.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/api/obj/Token.kt b/app/src/main/java/com/github/libretube/api/obj/Token.kt index 6f49ff7e8..a551dc727 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Token.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Token.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/db/DatabaseHelper.kt b/app/src/main/java/com/github/libretube/db/DatabaseHelper.kt index c6fdf259f..cbaf5e6f4 100644 --- a/app/src/main/java/com/github/libretube/db/DatabaseHelper.kt +++ b/app/src/main/java/com/github/libretube/db/DatabaseHelper.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/db/obj/CustomInstance.kt b/app/src/main/java/com/github/libretube/db/obj/CustomInstance.kt index 189b24a79..e2d9d9249 100644 --- a/app/src/main/java/com/github/libretube/db/obj/CustomInstance.kt +++ b/app/src/main/java/com/github/libretube/db/obj/CustomInstance.kt @@ -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 = "", diff --git a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt index 5e027a953..3ef94118b 100644 --- a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt +++ b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylist.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistItem.kt b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistItem.kt index c87db7b9c..f19effde5 100644 --- a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistItem.kt +++ b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistItem.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistWithVideos.kt b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistWithVideos.kt index 012617adf..671b477bd 100644 --- a/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistWithVideos.kt +++ b/app/src/main/java/com/github/libretube/db/obj/LocalPlaylistWithVideos.kt @@ -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( diff --git a/app/src/main/java/com/github/libretube/db/obj/LocalSubscription.kt b/app/src/main/java/com/github/libretube/db/obj/LocalSubscription.kt index 681779ad0..3fe2a1abb 100644 --- a/app/src/main/java/com/github/libretube/db/obj/LocalSubscription.kt +++ b/app/src/main/java/com/github/libretube/db/obj/LocalSubscription.kt @@ -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 = "" diff --git a/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt index 328270830..b44e0f5b2 100644 --- a/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt +++ b/app/src/main/java/com/github/libretube/db/obj/PlaylistBookmark.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/db/obj/SearchHistoryItem.kt b/app/src/main/java/com/github/libretube/db/obj/SearchHistoryItem.kt index 6a7d0d3c2..d677d2dbc 100644 --- a/app/src/main/java/com/github/libretube/db/obj/SearchHistoryItem.kt +++ b/app/src/main/java/com/github/libretube/db/obj/SearchHistoryItem.kt @@ -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 = "" diff --git a/app/src/main/java/com/github/libretube/db/obj/WatchHistoryItem.kt b/app/src/main/java/com/github/libretube/db/obj/WatchHistoryItem.kt index 45da337df..01a8bdd74 100644 --- a/app/src/main/java/com/github/libretube/db/obj/WatchHistoryItem.kt +++ b/app/src/main/java/com/github/libretube/db/obj/WatchHistoryItem.kt @@ -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 = "", diff --git a/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt b/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt index bf6a77396..2f6f0e050 100644 --- a/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt +++ b/app/src/main/java/com/github/libretube/db/obj/WatchPosition.kt @@ -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 = "", diff --git a/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt b/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt index 2be7bbde4..7f1e718b7 100644 --- a/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt +++ b/app/src/main/java/com/github/libretube/extensions/ToStreamItem.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/obj/BackupFile.kt b/app/src/main/java/com/github/libretube/obj/BackupFile.kt index 82e8a75ec..958b04b64 100644 --- a/app/src/main/java/com/github/libretube/obj/BackupFile.kt +++ b/app/src/main/java/com/github/libretube/obj/BackupFile.kt @@ -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? = null, - var watchPositions: List? = null, - var searchHistory: List? = null, - var localSubscriptions: List? = null, - var customInstances: List? = null, - var playlistBookmarks: List? = null, - var localPlaylists: List? = null, - var preferences: List? = null + var watchHistory: List = emptyList(), + var watchPositions: List = emptyList(), + var searchHistory: List = emptyList(), + var localSubscriptions: List = emptyList(), + var customInstances: List = emptyList(), + var playlistBookmarks: List = emptyList(), + var localPlaylists: List = emptyList(), + var preferences: List = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/obj/ImportPlaylist.kt b/app/src/main/java/com/github/libretube/obj/ImportPlaylist.kt index a080dfa30..e31622d32 100644 --- a/app/src/main/java/com/github/libretube/obj/ImportPlaylist.kt +++ b/app/src/main/java/com/github/libretube/obj/ImportPlaylist.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/obj/ImportPlaylistFile.kt b/app/src/main/java/com/github/libretube/obj/ImportPlaylistFile.kt index 43f9ff4a0..0693e2df6 100644 --- a/app/src/main/java/com/github/libretube/obj/ImportPlaylistFile.kt +++ b/app/src/main/java/com/github/libretube/obj/ImportPlaylistFile.kt @@ -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? = null + val format: String, + val version: Int, + val playlists: List = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/obj/NewPipeSubscription.kt b/app/src/main/java/com/github/libretube/obj/NewPipeSubscription.kt index 1db358271..c75befd6a 100644 --- a/app/src/main/java/com/github/libretube/obj/NewPipeSubscription.kt +++ b/app/src/main/java/com/github/libretube/obj/NewPipeSubscription.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/obj/NewPipeSubscriptions.kt b/app/src/main/java/com/github/libretube/obj/NewPipeSubscriptions.kt index 9c19551d2..8309b5f27 100644 --- a/app/src/main/java/com/github/libretube/obj/NewPipeSubscriptions.kt +++ b/app/src/main/java/com/github/libretube/obj/NewPipeSubscriptions.kt @@ -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? = null + @SerialName("app_version") val appVersion: String = "", + @SerialName("app_version_int") val appVersionInt: Int = 0, + val subscriptions: List = emptyList() ) diff --git a/app/src/main/java/com/github/libretube/obj/PreferenceItem.kt b/app/src/main/java/com/github/libretube/obj/PreferenceItem.kt index 7c547fea2..25bfd7ad4 100644 --- a/app/src/main/java/com/github/libretube/obj/PreferenceItem.kt +++ b/app/src/main/java/com/github/libretube/obj/PreferenceItem.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/obj/update/Asset.kt b/app/src/main/java/com/github/libretube/obj/update/Asset.kt index 1388df1c1..19102970f 100644 --- a/app/src/main/java/com/github/libretube/obj/update/Asset.kt +++ b/app/src/main/java/com/github/libretube/obj/update/Asset.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/obj/update/Author.kt b/app/src/main/java/com/github/libretube/obj/update/Author.kt deleted file mode 100644 index ae61b7660..000000000 --- a/app/src/main/java/com/github/libretube/obj/update/Author.kt +++ /dev/null @@ -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 -) diff --git a/app/src/main/java/com/github/libretube/obj/update/Reactions.kt b/app/src/main/java/com/github/libretube/obj/update/Reactions.kt index 0ec667860..01cfdc21e 100644 --- a/app/src/main/java/com/github/libretube/obj/update/Reactions.kt +++ b/app/src/main/java/com/github/libretube/obj/update/Reactions.kt @@ -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 ) diff --git a/app/src/main/java/com/github/libretube/obj/update/UpdateInfo.kt b/app/src/main/java/com/github/libretube/obj/update/UpdateInfo.kt index 8491dc734..6d166add7 100644 --- a/app/src/main/java/com/github/libretube/obj/update/UpdateInfo.kt +++ b/app/src/main/java/com/github/libretube/obj/update/UpdateInfo.kt @@ -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? = 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 = 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 ) diff --git a/app/src/main/java/com/github/libretube/obj/update/Uploader.kt b/app/src/main/java/com/github/libretube/obj/update/Uploader.kt deleted file mode 100644 index 9dc63930b..000000000 --- a/app/src/main/java/com/github/libretube/obj/update/Uploader.kt +++ /dev/null @@ -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 -) diff --git a/app/src/main/java/com/github/libretube/obj/update/User.kt b/app/src/main/java/com/github/libretube/obj/update/User.kt new file mode 100644 index 000000000..b2103e904 --- /dev/null +++ b/app/src/main/java/com/github/libretube/obj/update/User.kt @@ -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 +) diff --git a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt index 8378e9128..d1413db69 100644 --- a/app/src/main/java/com/github/libretube/services/BackgroundMode.kt +++ b/app/src/main/java/com/github/libretube/services/BackgroundMode.kt @@ -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,11 +319,10 @@ class BackgroundMode : Service() { runCatching { val categories = PlayerHelper.getSponsorBlockCategories() if (categories.isEmpty()) return@runCatching - segmentData = - RetrofitInstance.api.getSegments( - videoId, - ObjectMapper().writeValueAsString(categories) - ) + segmentData = RetrofitInstance.api.getSegments( + videoId, + JsonHelper.json.encodeToString(categories) + ) checkForSegments() } } diff --git a/app/src/main/java/com/github/libretube/services/DownloadService.kt b/app/src/main/java/com/github/libretube/services/DownloadService.kt index b35fae1a5..64a75c03a 100644 --- a/app/src/main/java/com/github/libretube/services/DownloadService.kt +++ b/app/src/main/java/com/github/libretube/services/DownloadService.kt @@ -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, - thumbnailTargetFile.absolutePath - ) - } + ImageHelper.downloadImage( + this@DownloadService, + streams.thumbnailUrl, + thumbnailTargetFile.absolutePath + ) val downloadItems = streams.toDownloadItems( videoId, diff --git a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt index 73502253b..ec33f5cf5 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt @@ -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 } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt index 6ffa9da7e..c99229616 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/SearchAdapter.kt @@ -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( diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/BackupDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/BackupDialog.kt index 12e1ab34d..9518fbcc5 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/BackupDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/BackupDialog.kt @@ -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) } }) } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/DeleteAccountDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/DeleteAccountDialog.kt index 3613aabee..89d1e5ae1 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/DeleteAccountDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/DeleteAccountDialog.kt @@ -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() diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/DownloadDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/DownloadDialog.kt index 0a0ac45cf..e165e1f47 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/DownloadDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/DownloadDialog.kt @@ -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() @@ -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()) } diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/LoginDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/LoginDialog.kt index d0306a2a8..b6287ce05 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/LoginDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/LoginDialog.kt @@ -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() diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/UpdateDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/UpdateDialog.kt index 88c1d636d..43c2acf51 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/UpdateDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/UpdateDialog.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt index 3164fbafd..22c29884e 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/ChannelFragment.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt index 3df84e776..fdd295f8a 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlayerFragment.kt @@ -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() - initializeChapters() - } + 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 ) ) } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt index 39e5aca75..a5f8b476a 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/PlaylistFragment.kt @@ -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 } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt index 4eefe16d2..54a84c9b8 100644 --- a/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt +++ b/app/src/main/java/com/github/libretube/ui/fragments/SearchResultFragment.kt @@ -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) } } } diff --git a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt index b8f4246b2..016b00ff0 100644 --- a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt +++ b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/ui/preferences/BackupRestoreSettings.kt b/app/src/main/java/com/github/libretube/ui/preferences/BackupRestoreSettings.kt index 9aa6bb95e..0673081e7 100644 --- a/app/src/main/java/com/github/libretube/ui/preferences/BackupRestoreSettings.kt +++ b/app/src/main/java/com/github/libretube/ui/preferences/BackupRestoreSettings.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/ui/preferences/InstanceSettings.kt b/app/src/main/java/com/github/libretube/ui/preferences/InstanceSettings.kt index a7931a840..d42d7da5e 100644 --- a/app/src/main/java/com/github/libretube/ui/preferences/InstanceSettings.kt +++ b/app/src/main/java/com/github/libretube/ui/preferences/InstanceSettings.kt @@ -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 diff --git a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt index 987cfbf7a..f3edef523 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/ChannelOptionsBottomSheet.kt @@ -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, diff --git a/app/src/main/java/com/github/libretube/util/BackupHelper.kt b/app/src/main/java/com/github/libretube/util/BackupHelper.kt index 036d867d4..51ff6a1b3 100644 --- a/app/src/main/java/com/github/libretube/util/BackupHelper.kt +++ b/app/src/main/java/com/github/libretube/util/BackupHelper.kt @@ -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 - try { - context.contentResolver.openFileDescriptor(uri, "w")?.use { - FileOutputStream(it.fileDescriptor).use { fileOutputStream -> - fileOutputStream.write( - ObjectMapper().writeValueAsBytes(backupFile) - ) + fun createAdvancedBackup(uri: Uri?, backupFile: BackupFile) { + uri?.let { + try { + context.contentResolver.openOutputStream(it)?.use { outputStream -> + JsonHelper.json.encodeToStream(backupFile, outputStream) } + } catch (e: Exception) { + Log.e(TAG(), "Error while writing backup: $e") } - } catch (e: Exception) { - e.printStackTrace() } } @@ -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(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) } } } diff --git a/app/src/main/java/com/github/libretube/util/ImportHelper.kt b/app/src/main/java/com/github/libretube/util/ImportHelper.kt index 0db3c1068..9560b7fca 100644 --- a/app/src/main/java/com/github/libretube/util/ImportHelper.kt +++ b/app/src/main/java/com/github/libretube/util/ImportHelper.kt @@ -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(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() - 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(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) - ) - } - } - } } diff --git a/app/src/main/java/com/github/libretube/util/MetadataHelper.kt b/app/src/main/java/com/github/libretube/util/MetadataHelper.kt deleted file mode 100644 index a2b46d13d..000000000 --- a/app/src/main/java/com/github/libretube/util/MetadataHelper.kt +++ /dev/null @@ -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 - } - } -} diff --git a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt index 31769d384..99981aeda 100644 --- a/app/src/main/java/com/github/libretube/util/PlayingQueue.kt +++ b/app/src/main/java/com/github/libretube/util/PlayingQueue.kt @@ -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) diff --git a/app/src/main/java/com/github/libretube/util/TextUtils.kt b/app/src/main/java/com/github/libretube/util/TextUtils.kt index 201a2957a..9bc33799b 100644 --- a/app/src/main/java/com/github/libretube/util/TextUtils.kt +++ b/app/src/main/java/com/github/libretube/util/TextUtils.kt @@ -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) } /** diff --git a/build.gradle b/build.gradle index e3650b340..81dd9b027 100644 --- a/build.gradle +++ b/build.gradle @@ -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 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 799a499bf..01e43147d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" } @@ -46,4 +46,7 @@ lifecycle-viewmodel = { group = "androidx.lifecycle", name = "lifecycle-viewmode lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycle" } 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" } \ No newline at end of file +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" } \ No newline at end of file