Remove remaining Jackson code.

This commit is contained in:
Isira Seneviratne 2023-01-19 14:08:21 +05:30
parent e047d5babd
commit 60706c2d87
26 changed files with 136 additions and 145 deletions

View File

@ -108,10 +108,8 @@ 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

View File

@ -0,0 +1,9 @@
package com.github.libretube.api
import kotlinx.serialization.json.Json
object JsonHelper {
val json = Json {
ignoreUnknownKeys = true
}
}

View File

@ -4,28 +4,22 @@ 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 kotlinx.serialization.json.Json
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()
private val jacksonConverterFactory = JacksonConverterFactory.create()
private val json = Json {
ignoreUnknownKeys = true
}
private val kotlinxConverterFactory = json.asConverterFactory("application/json".toMediaType())
private val kotlinxConverterFactory = JsonHelper.json
.asConverterFactory("application/json".toMediaType())
val api by resettableLazy(lazyMgr) {
Retrofit.Builder()
.baseUrl(url)
.callFactory(CronetHelper.callFactory)
.addConverterFactory(kotlinxConverterFactory)
.addConverterFactory(jacksonConverterFactory)
.build()
.create<PipedApi>()
}
@ -35,7 +29,6 @@ object RetrofitInstance {
.baseUrl(authUrl)
.callFactory(CronetHelper.callFactory)
.addConverterFactory(kotlinxConverterFactory)
.addConverterFactory(jacksonConverterFactory)
.build()
.create<PipedApi>()
}
@ -45,7 +38,6 @@ object RetrofitInstance {
.baseUrl(url)
.callFactory(CronetHelper.callFactory)
.addConverterFactory(kotlinxConverterFactory)
.addConverterFactory(jacksonConverterFactory)
.build()
.create<ExternalApi>()
}

View File

@ -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 = "",

View File

@ -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)

View File

@ -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,

View File

@ -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(

View File

@ -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 = ""

View File

@ -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

View File

@ -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 = ""

View File

@ -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 = "",

View File

@ -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 = "",

View File

@ -7,14 +7,16 @@ import com.github.libretube.db.obj.PlaylistBookmark
import com.github.libretube.db.obj.SearchHistoryItem
import com.github.libretube.db.obj.WatchHistoryItem
import com.github.libretube.db.obj.WatchPosition
import kotlinx.serialization.Serializable
@Serializable
data class BackupFile(
var watchHistory: List<WatchHistoryItem>? = null,
var watchPositions: List<WatchPosition>? = null,
var searchHistory: List<SearchHistoryItem>? = null,
var localSubscriptions: List<LocalSubscription>? = null,
var customInstances: List<CustomInstance>? = null,
var playlistBookmarks: List<PlaylistBookmark>? = null,
var localPlaylists: List<LocalPlaylistWithVideos>? = null,
var preferences: List<PreferenceItem>? = null
var watchHistory: List<WatchHistoryItem> = emptyList(),
var watchPositions: List<WatchPosition> = emptyList(),
var searchHistory: List<SearchHistoryItem> = emptyList(),
var localSubscriptions: List<LocalSubscription> = emptyList(),
var customInstances: List<CustomInstance> = emptyList(),
var playlistBookmarks: List<PlaylistBookmark> = emptyList(),
var localPlaylists: List<LocalPlaylistWithVideos> = emptyList(),
var preferences: List<PreferenceItem> = emptyList()
)

View File

@ -3,5 +3,5 @@ package com.github.libretube.obj
data class ImportPlaylistFile(
val format: String? = null,
val version: Int? = null,
val playlists: List<ImportPlaylist>? = null
val playlists: List<ImportPlaylist> = emptyList()
)

View File

@ -1,5 +1,8 @@
package com.github.libretube.obj
import kotlinx.serialization.Serializable
@Serializable
data class NewPipeSubscription(
val name: String? = null,
val service_id: Int? = null,

View File

@ -1,7 +1,10 @@
package com.github.libretube.obj
import kotlinx.serialization.Serializable
@Serializable
data class NewPipeSubscriptions(
val app_version: String = "",
val app_version_int: Int = 0,
val subscriptions: List<NewPipeSubscription>? = null
val subscriptions: List<NewPipeSubscription> = emptyList()
)

View File

@ -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
)

View File

@ -3,6 +3,8 @@ package com.github.libretube.obj.update
import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonNull
@Serializable
data class Asset(
@ -11,7 +13,7 @@ data class Asset(
@SerialName("created_at") val createdAt: Instant,
@SerialName("download_count") val downloadCount: Int,
val id: Int,
val label: String? = null,
val label: JsonElement = JsonNull,
val name: String,
@SerialName("node_id") val nodeId: String,
val size: Int,

View File

@ -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
@ -43,6 +43,7 @@ import com.google.android.exoplayer2.audio.AudioAttributes
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.
@ -335,11 +336,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()
}
}

View File

@ -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)
}
})
}

View File

@ -34,9 +34,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
@ -117,6 +117,7 @@ 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
@ -744,7 +745,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)

View File

@ -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)

View File

@ -2,15 +2,23 @@ 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.contentOrNull
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 +27,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 +43,33 @@ class BackupHelper(private val context: Context) {
* Restore data from a [BackupFile]
*/
fun restoreAdvancedBackup(uri: Uri?) {
if (uri == null) return
val mapper = ObjectMapper()
val json = context.contentResolver.openInputStream(uri)?.use {
it.bufferedReader().use { reader -> reader.readText() }
}.orEmpty()
val backupFile = mapper.readValue(json, BackupFile::class.java)
val backupFile = uri?.let {
context.contentResolver.openInputStream(it)?.use { inputStream ->
JsonHelper.json.decodeFromStream<BackupFile>(inputStream)
}
} ?: return
query {
Database.watchHistoryDao().insertAll(
*backupFile.watchHistory.orEmpty().toTypedArray()
*backupFile.watchHistory.toTypedArray()
)
Database.searchHistoryDao().insertAll(
*backupFile.searchHistory.orEmpty().toTypedArray()
*backupFile.searchHistory.toTypedArray()
)
Database.watchPositionDao().insertAll(
*backupFile.watchPositions.orEmpty().toTypedArray()
*backupFile.watchPositions.toTypedArray()
)
Database.localSubscriptionDao().insertAll(
*backupFile.localSubscriptions.orEmpty().toTypedArray()
*backupFile.localSubscriptions.toTypedArray()
)
Database.customInstanceDao().insertAll(
*backupFile.customInstances.orEmpty().toTypedArray()
*backupFile.customInstances.toTypedArray()
)
Database.playlistBookmarkDao().insertAll(
*backupFile.playlistBookmarks.orEmpty().toTypedArray()
*backupFile.playlistBookmarks.toTypedArray()
)
backupFile.localPlaylists?.forEach {
backupFile.localPlaylists.forEach {
Database.localPlaylistsDao().createPlaylist(it.playlist)
val playlistId = Database.localPlaylistsDao().getAll().last().playlist.id
it.videos.forEach {
@ -91,17 +93,22 @@ class BackupHelper(private val context: Context) {
// 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)
val value = it.value.booleanOrNull
?: it.value.floatOrNull
?: it.value.longOrNull
?: it.value.intOrNull
?: it.value.contentOrNull
when (value) {
is Boolean -> putBoolean(it.key, value)
is Float -> putFloat(it.key, value)
is Long -> putLong(it.key, value)
is Int -> {
when (it.key) {
PreferenceKeys.START_FRAGMENT -> putInt(it.key, it.value)
else -> putLong(it.key, it.value.toLong())
PreferenceKeys.START_FRAGMENT -> putInt(it.key, value)
else -> putLong(it.key, value.toLong())
}
}
is String -> putString(it.key, it.value)
is String -> putString(it.key, value)
}
}
}

View File

@ -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,14 @@ 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.decodeFromString
import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream
import okio.use
class ImportHelper(
private val activity: Activity
@ -56,11 +59,10 @@ class ImportHelper(
return when (val fileType = activity.contentResolver.getType(uri)) {
"application/json", "application/*", "application/octet-stream" -> {
// NewPipe subscriptions format
val subscriptions = ObjectMapper().readValue(
uri.readText(),
NewPipeSubscriptions::class.java
)
subscriptions.subscriptions.orEmpty().map {
val subscriptions = activity.contentResolver.openInputStream(uri)?.use {
JsonHelper.json.decodeFromStream<NewPipeSubscriptions>(it)
}
subscriptions?.subscriptions.orEmpty().map {
it.url!!.replace("https://www.youtube.com/channel/", "")
}
}
@ -104,7 +106,9 @@ class ImportHelper(
subscriptions = newPipeChannels
)
uri.write(newPipeSubscriptions)
activity.contentResolver.openOutputStream(uri)?.use {
JsonHelper.json.encodeToStream<Any>(newPipeSubscriptions, it)
}
activity.toastFromMainThread(R.string.exportsuccess)
}
@ -134,11 +138,9 @@ class ImportHelper(
}
}
"application/json", "application/*", "application/octet-stream" -> {
val playlistFile = ObjectMapper().readValue(
uri.readText(),
ImportPlaylistFile::class.java
)
importPlaylists.addAll(playlistFile.playlists.orEmpty())
val playlistFile = JsonHelper.json
.decodeFromString<ImportPlaylistFile>(uri.readText())
importPlaylists.addAll(playlistFile.playlists)
}
else -> {
activity.applicationContext.toastFromMainThread("Unsupported file type $fileType")
@ -173,7 +175,9 @@ class ImportHelper(
playlists = playlists
)
uri.write(playlistFile)
activity.contentResolver.openOutputStream(uri)?.use {
JsonHelper.json.encodeToStream<Any>(playlistFile, it)
}
activity.toastFromMainThread(R.string.exportsuccess)
}
@ -184,14 +188,4 @@ class ImportHelper(
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)
)
}
}
}
}

View File

@ -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
}
}
}

View File

@ -11,7 +11,6 @@ espresso = "3.5.1"
workRuntime = "2.7.1"
exoplayer = "2.18.2"
retrofit = "2.9.0"
jacksonAnnotations = "2.13.4"
desugaring = "1.2.2"
cronetEmbedded = "108.5359.79"
cronetOkHttp = "0.1.0"
@ -36,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" }