From 1ccb857f2a02a60f8f77b013ab51b7daac1b5332 Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Sat, 7 Oct 2023 04:54:18 +0530 Subject: [PATCH 1/2] fix: Properly parse date strings --- .../com/github/libretube/api/obj/Streams.kt | 11 ++++--- .../com/github/libretube/db/Converters.kt | 8 ++--- .../github/libretube/extensions/LocalDate.kt | 3 -- .../libretube/json/SafeLocalDateSerializer.kt | 32 +++++++++++++++++++ .../libretube/services/DownloadService.kt | 3 +- 5 files changed, 43 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt 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 aa4ef6fce..e704090a5 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 @@ -2,18 +2,19 @@ package com.github.libretube.api.obj import com.github.libretube.db.obj.DownloadItem import com.github.libretube.enums.FileType -import com.github.libretube.extensions.toLocalDateSafe import com.github.libretube.extensions.toMillis import com.github.libretube.helpers.ProxyHelper +import com.github.libretube.json.SafeLocalDateSerializer import com.github.libretube.parcelable.DownloadData -import kotlin.io.path.Path +import kotlinx.datetime.LocalDate import kotlinx.serialization.Serializable +import kotlin.io.path.Path @Serializable data class Streams( val title: String, val description: String, - val uploadDate: String, + @Serializable(SafeLocalDateSerializer::class) val uploadDate: LocalDate, val uploader: String, val uploaderUrl: String, val uploaderAvatar: String? = null, @@ -84,8 +85,8 @@ data class Streams( uploaderName = uploader, uploaderUrl = uploaderUrl, uploaderAvatar = uploaderAvatar, - uploadedDate = uploadDate, - uploaded = uploadDate.toLocalDateSafe().toMillis(), + uploadedDate = uploadDate.toString(), + uploaded = uploadDate.toMillis(), duration = duration, views = views, uploaderVerified = uploaderVerified, diff --git a/app/src/main/java/com/github/libretube/db/Converters.kt b/app/src/main/java/com/github/libretube/db/Converters.kt index c3e56a690..71bfb289a 100644 --- a/app/src/main/java/com/github/libretube/db/Converters.kt +++ b/app/src/main/java/com/github/libretube/db/Converters.kt @@ -2,18 +2,18 @@ package com.github.libretube.db import androidx.room.TypeConverter import com.github.libretube.api.JsonHelper -import com.github.libretube.extensions.toLocalDateSafe +import kotlinx.datetime.LocalDate +import kotlinx.datetime.toLocalDate +import kotlinx.serialization.encodeToString import java.nio.file.Path import kotlin.io.path.Path -import kotlinx.datetime.LocalDate -import kotlinx.serialization.encodeToString object Converters { @TypeConverter fun localDateToString(localDate: LocalDate?) = localDate?.toString() @TypeConverter - fun stringToLocalDate(string: String?) = string?.toLocalDateSafe() + fun stringToLocalDate(string: String?) = string?.toLocalDate() @TypeConverter fun pathToString(path: Path?) = path?.toString() diff --git a/app/src/main/java/com/github/libretube/extensions/LocalDate.kt b/app/src/main/java/com/github/libretube/extensions/LocalDate.kt index 338cec6c7..370d9a17a 100644 --- a/app/src/main/java/com/github/libretube/extensions/LocalDate.kt +++ b/app/src/main/java/com/github/libretube/extensions/LocalDate.kt @@ -3,8 +3,5 @@ package com.github.libretube.extensions import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import kotlinx.datetime.atStartOfDayIn -import kotlinx.datetime.toLocalDate fun LocalDate.toMillis() = this.atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds() - -fun String.toLocalDateSafe() = this.substring(0, 10).toLocalDate() diff --git a/app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt b/app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt new file mode 100644 index 000000000..f38e30964 --- /dev/null +++ b/app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt @@ -0,0 +1,32 @@ +package com.github.libretube.json + +import android.util.Log +import com.github.libretube.extensions.TAG +import kotlinx.datetime.LocalDate +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toInstant +import kotlinx.datetime.toLocalDate +import kotlinx.datetime.toLocalDateTime +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind.STRING +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +object SafeLocalDateSerializer : KSerializer { + override val descriptor = PrimitiveSerialDescriptor("LocalDate", STRING) + + override fun deserialize(decoder: Decoder): LocalDate { + val string = decoder.decodeString() + return try { + string.toLocalDate() + } catch (e: IllegalArgumentException) { + Log.e(TAG(), "Error parsing date '$string'", e) + string.toInstant().toLocalDateTime(TimeZone.currentSystemDefault()).date + } + } + + override fun serialize(encoder: Encoder, value: LocalDate) { + encoder.encodeString(value.toString()) + } +} 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 8e28534b4..98689be01 100644 --- a/app/src/main/java/com/github/libretube/services/DownloadService.kt +++ b/app/src/main/java/com/github/libretube/services/DownloadService.kt @@ -28,7 +28,6 @@ import com.github.libretube.enums.FileType import com.github.libretube.extensions.formatAsFileSize import com.github.libretube.extensions.getContentLength import com.github.libretube.extensions.parcelableExtra -import com.github.libretube.extensions.toLocalDateSafe import com.github.libretube.extensions.toastFromMainThread import com.github.libretube.helpers.DownloadHelper import com.github.libretube.helpers.DownloadHelper.getNotificationId @@ -116,7 +115,7 @@ class DownloadService : LifecycleService() { streams.title, streams.description, streams.uploader, - streams.uploadDate.toLocalDateSafe(), + streams.uploadDate, thumbnailTargetPath ) Database.downloadDao().insertDownload(download) From 36ae0e867c8bcfb873beff643318083c07bcaedb Mon Sep 17 00:00:00 2001 From: Isira Seneviratne Date: Wed, 18 Oct 2023 06:17:57 +0530 Subject: [PATCH 2/2] refactor: Obtain stream upload date as an Instant --- .../com/github/libretube/api/obj/Streams.kt | 19 +++++++++++++------ ...Serializer.kt => SafeInstantSerializer.kt} | 16 ++++++++-------- .../libretube/services/DownloadService.kt | 4 +++- .../libretube/ui/views/DescriptionLayout.kt | 6 ++++-- 4 files changed, 28 insertions(+), 17 deletions(-) rename app/src/main/java/com/github/libretube/json/{SafeLocalDateSerializer.kt => SafeInstantSerializer.kt} (61%) 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 e704090a5..1607cc204 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 @@ -2,11 +2,13 @@ package com.github.libretube.api.obj import com.github.libretube.db.obj.DownloadItem import com.github.libretube.enums.FileType -import com.github.libretube.extensions.toMillis import com.github.libretube.helpers.ProxyHelper -import com.github.libretube.json.SafeLocalDateSerializer +import com.github.libretube.json.SafeInstantSerializer import com.github.libretube.parcelable.DownloadData -import kotlinx.datetime.LocalDate +import kotlinx.datetime.Instant +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime +import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlin.io.path.Path @@ -14,7 +16,11 @@ import kotlin.io.path.Path data class Streams( val title: String, val description: String, - @Serializable(SafeLocalDateSerializer::class) val uploadDate: LocalDate, + + @Serializable(SafeInstantSerializer::class) + @SerialName("uploadDate") + val uploadTimestamp: Instant, + val uploader: String, val uploaderUrl: String, val uploaderAvatar: String? = null, @@ -85,8 +91,9 @@ data class Streams( uploaderName = uploader, uploaderUrl = uploaderUrl, uploaderAvatar = uploaderAvatar, - uploadedDate = uploadDate.toString(), - uploaded = uploadDate.toMillis(), + uploadedDate = uploadTimestamp.toLocalDateTime(TimeZone.currentSystemDefault()).date + .toString(), + uploaded = uploadTimestamp.toEpochMilliseconds(), duration = duration, views = views, uploaderVerified = uploaderVerified, diff --git a/app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt b/app/src/main/java/com/github/libretube/json/SafeInstantSerializer.kt similarity index 61% rename from app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt rename to app/src/main/java/com/github/libretube/json/SafeInstantSerializer.kt index f38e30964..0d063bb20 100644 --- a/app/src/main/java/com/github/libretube/json/SafeLocalDateSerializer.kt +++ b/app/src/main/java/com/github/libretube/json/SafeInstantSerializer.kt @@ -2,31 +2,31 @@ package com.github.libretube.json import android.util.Log import com.github.libretube.extensions.TAG -import kotlinx.datetime.LocalDate +import kotlinx.datetime.Instant import kotlinx.datetime.TimeZone +import kotlinx.datetime.atStartOfDayIn import kotlinx.datetime.toInstant import kotlinx.datetime.toLocalDate -import kotlinx.datetime.toLocalDateTime import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.PrimitiveKind.STRING import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder -object SafeLocalDateSerializer : KSerializer { - override val descriptor = PrimitiveSerialDescriptor("LocalDate", STRING) +object SafeInstantSerializer : KSerializer { + override val descriptor = PrimitiveSerialDescriptor("Instant", STRING) - override fun deserialize(decoder: Decoder): LocalDate { + override fun deserialize(decoder: Decoder): Instant { val string = decoder.decodeString() return try { - string.toLocalDate() + string.toInstant() } catch (e: IllegalArgumentException) { Log.e(TAG(), "Error parsing date '$string'", e) - string.toInstant().toLocalDateTime(TimeZone.currentSystemDefault()).date + string.toLocalDate().atStartOfDayIn(TimeZone.currentSystemDefault()) } } - override fun serialize(encoder: Encoder, value: LocalDate) { + override fun serialize(encoder: Encoder, value: Instant) { encoder.encodeString(value.toString()) } } 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 98689be01..148fbe1c9 100644 --- a/app/src/main/java/com/github/libretube/services/DownloadService.kt +++ b/app/src/main/java/com/github/libretube/services/DownloadService.kt @@ -62,6 +62,8 @@ import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime import okio.buffer import okio.sink import okio.source @@ -115,7 +117,7 @@ class DownloadService : LifecycleService() { streams.title, streams.description, streams.uploader, - streams.uploadDate, + streams.uploadTimestamp.toLocalDateTime(TimeZone.currentSystemDefault()).date, thumbnailTargetPath ) Database.downloadDao().insertDownload(download) diff --git a/app/src/main/java/com/github/libretube/ui/views/DescriptionLayout.kt b/app/src/main/java/com/github/libretube/ui/views/DescriptionLayout.kt index 9df407cdc..627df76f3 100644 --- a/app/src/main/java/com/github/libretube/ui/views/DescriptionLayout.kt +++ b/app/src/main/java/com/github/libretube/ui/views/DescriptionLayout.kt @@ -15,11 +15,12 @@ import com.github.libretube.R import com.github.libretube.api.obj.Streams import com.github.libretube.databinding.DescriptionLayoutBinding import com.github.libretube.extensions.formatShort -import com.github.libretube.extensions.toLocalDateSafe import com.github.libretube.ui.activities.VideoTagsAdapter import com.github.libretube.util.HtmlParser import com.github.libretube.util.LinkHandler import com.github.libretube.util.TextUtils +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime import java.util.Locale class DescriptionLayout( @@ -135,7 +136,8 @@ class DescriptionLayout( private fun localizeDate(streams: Streams): String { if (streams.livestream) return "" - return TextUtils.SEPARATOR + TextUtils.localizeDate(streams.uploadDate.toLocalDateSafe()) + val date = streams.uploadTimestamp.toLocalDateTime(TimeZone.currentSystemDefault()).date + return TextUtils.SEPARATOR + TextUtils.localizeDate(date) } companion object {